+ Moved visual SLE props from LogicCore to EdgeControl

This commit is contained in:
panthernet 2015-06-11 16:55:28 +03:00
Родитель 01489d5461
Коммит 6db1d624c8
14 изменённых файлов: 93 добавлений и 98 удалений

Просмотреть файл

@ -30,7 +30,7 @@ DETAILED CHANGELOG:
+ Added GraphArea::PreloadGraph() method for manual graph rendering which generate vertices and edges from GraphArea::LogicCore.Graph property
w/o any algorithms and also sets custom vertices positions if needed [WPF, METRO]
+ Added new EdgeControl template PART (PART_SelfLoopedEdge) for custom self looped edge indicator visualization. It represents FrameworkElement and if specified in the template
will be positioned in the top left vertex corner [WPF, METRO]
will be positioned in the top left vertex corner. Also made indicator settings more flexible by implementing some dependency props [WPF, METRO]
+ Added StateStorage::SaveOrUpdateState() method for easier use [WPF,METRO]
+ Fixed first time solution rebuild problems by referencing new QuickGraphPCL nuget [ALL]
+ Fixed layout algorithm calculations to always receive actual vertex positions as input parameter
@ -74,9 +74,10 @@ BREAKING CHANGES:
* Now GraphX for WPF requires only .NET Framework 4.0 to build & run
* EdgeLabelControl no longer needs default Angle binding and RenderTransformOrigin setup. They are processed internally [WPF]
* GraphArea::GenerateGraph() method now has generateAllEdges param True by default.
* Renamed following peoperties:
* EdgeControl & LogicCore::EdgeSelfLoopCircleOffset -> EdgeSelfLoopElementOffset
* EdgeControl & LogicCore::EdgeSelfLoopCircleRadius -> EdgeSelfLoopElementRadius
* Renamed following peoperties, moved them to EdgeControlBase and implemented them as DependencyProperty:
* LogicCore::EdgeSelfLoopCircleOffset -> SelfLoopIndicatorOffset
* LogicCore::EdgeSelfLoopCircleRadius -> SelfLoopIndicatorRadius
* LogicCore::EdgeShowSelfLooped -> ShowSelfLoopIndicator
* Completely deprecated EdgeControl::PART_edgeArrowPath template PART in favor of the new DefaultEdgePointer (PART_EdgePointerForSource & PART_EdgePointerForTarget).
Please renew your custom templates. You can find an example in Generic.XAML template.
* Self looped edges display logic has been slightly changed with the introduction of custom template PART (PART_SelfLoopedEdge). Now LogicCore::EdgeSelfLoopElementOffset

Просмотреть файл

@ -116,6 +116,13 @@
<Path Data="M0,0.5 L1,1 1,0" Fill="Yellow" Stretch="Uniform" Width="15" Height="15"/>
</controls1:DefaultEdgePointer>
<Path x:Name="PART_SelfLoopedEdge"
Width="10"
Height="10"
Stretch="Uniform"
Fill="{TemplateBinding Foreground}"
Data="F1 M 17.4167,32.25L 32.9107,32.25L 38,18L 43.0893,32.25L 58.5833,32.25L 45.6798,41.4944L 51.4583,56L 38,48.0833L 26.125,56L 30.5979,41.7104L 17.4167,32.25 Z "/>
<controls1:EdgeLabelControl x:Name="PART_edgeLabel"
Content="{Binding Text}"
Opacity="{Binding VisualEdgeTransparency}"

Просмотреть файл

@ -174,6 +174,8 @@ namespace METRO.SimpleGraph
}
vlist = dataGraph.Vertices.ToList();
AddEdge(dataGraph, 0, 1, vlist);
AddEdge(dataGraph, 0, 0, vlist);
AddEdge(dataGraph, 0, 2, vlist);
AddEdge(dataGraph, 1, 3, vlist);
AddEdge(dataGraph, 1, 4, vlist);

Просмотреть файл

@ -275,6 +275,7 @@ namespace ShowcaseApp.WPF.Pages
{
gg_Area.ClearLayout();
var graph = ShowcaseHelper.GenerateDataGraph(Convert.ToInt32(gg_vertexCount.Text));
graph.AddEdge(new DataEdge(graph.Vertices.First(), graph.Vertices.First()));
//assign graph again as we need to update Graph param inside and i have no independent examples
if (gg_Area.LogicCore.ExternalLayoutAlgorithm != null)
AssignExternalLayoutAlgorithm(graph);

Просмотреть файл

@ -36,6 +36,7 @@
<!-- EDGE CONTROL -->
<Style TargetType="{x:Type controls:EdgeControl}">
<Setter Property="SelfLoopIndicatorOffset" Value="10,10"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:EdgeControl}">
@ -52,6 +53,7 @@
Height="10"
Stretch="Uniform"
Fill="Black"
IsHitTestVisible="True"
ToolTip="This vertex has some self looped edges!"
Data="F1 M 17.4167,32.25L 32.9107,32.25L 38,18L 43.0893,32.25L 58.5833,32.25L 45.6798,41.4944L 51.4583,56L 38,48.0833L 26.125,56L 30.5979,41.7104L 17.4167,32.25 Z "/>
</Grid>

Просмотреть файл

@ -84,7 +84,7 @@ namespace GraphX.Controls
DragBehaviour.SetIsDragEnabled(this, false);
_linegeometry = null;
_linePathObject = null;
SelfLoopedEdgeElement = null;
SelfLoopIndicator = null;
if (_edgeLabelControl != null)
{
_edgeLabelControl.Dispose();

Просмотреть файл

@ -31,19 +31,33 @@ namespace GraphX.Controls
[TemplatePart(Name = "PART_EdgePointerForTarget", Type = typeof(IEdgePointer))]
public abstract class EdgeControlBase : Control, IGraphControl, IDisposable
{
public abstract bool IsSelfLooped { get; protected set; }
public abstract void Dispose();
public abstract void Clean();
protected virtual void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
protected virtual void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
#if METRO
void IPositionChangeNotify.OnPositionChanged()
{
//skip any actions on own position change
}
#endif
#region Properties & Fields
public abstract bool IsSelfLooped { get; protected set; }
public abstract void Dispose();
public abstract void Clean();
protected DoubleCollection StrokeDashArray { get; set; }
/// <summary>
/// Element presenting self looped edge
/// </summary>
protected FrameworkElement SelfLoopIndicator;
/// <summary>
/// Used to store last known SLE rect size for proper updates on layout passes
/// </summary>
private SysRect _selfLoopedEdgeLastKnownRect;
protected virtual void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
protected virtual void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
/// <summary>
/// Gets or sets parent GraphArea visual
/// </summary>
@ -56,17 +70,45 @@ namespace GraphX.Controls
public static readonly DependencyProperty RootCanvasProperty =
DependencyProperty.Register("RootArea", typeof(GraphAreaBase), typeof(EdgeControlBase), new PropertyMetadata(null));
/// <summary>
/// Element presenting self looped edge
/// </summary>
protected FrameworkElement SelfLoopedEdgeElement;
public static readonly DependencyProperty SelfLoopIndicatorRadiusProperty = DependencyProperty.Register("SelfLoopIndicatorRadius",
typeof(double),
typeof(EdgeControlBase),
new PropertyMetadata(5d));
/// <summary>
/// Used to store last known SLE rect size for proper updates on layout passes
/// Radius of a self-loop edge, which is drawn as a circle. Default is 20.
/// </summary>
private SysRect _selfLoopedEdgeLastKnownRect;
public double SelfLoopIndicatorRadius {
get { return (double)GetValue(SelfLoopIndicatorRadiusProperty); }
set { SetValue(SelfLoopIndicatorRadiusProperty, value); }
}
public static readonly DependencyProperty SelfLoopIndicatorOffsetProperty = DependencyProperty.Register("SelfLoopIndicatorOffset",
typeof(Point),
typeof(EdgeControlBase),
new PropertyMetadata(new Point()));
/// <summary>
/// Offset from the corner of the vertex. Useful for custom vertex shapes. Default is 10,10.
/// </summary>
public Point SelfLoopIndicatorOffset
{
get { return (Point)GetValue(SelfLoopIndicatorOffsetProperty); }
set { SetValue(SelfLoopIndicatorOffsetProperty, value); }
}
public static readonly DependencyProperty ShowSelfLoopIndicatorProperty = DependencyProperty.Register("ShowSelfLoopIndicator",
typeof(bool),
typeof(EdgeControlBase),
new PropertyMetadata(true));
/// <summary>
/// Show self looped edges on vertices. Default value is true.
/// </summary>
public bool ShowSelfLoopIndicator
{
get { return (bool)GetValue(ShowSelfLoopIndicatorProperty); }
set { SetValue(ShowSelfLoopIndicatorProperty, value); }
}
#region Properties
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source",
typeof(VertexControl),
@ -153,7 +195,6 @@ namespace GraphX.Controls
ec.UpdateEdge(false);
}
protected DoubleCollection StrokeDashArray { get; set; }
/// <summary>
/// Gets or sets edge dash style
@ -411,16 +452,16 @@ namespace GraphX.Controls
_edgePointerForSource = GetTemplatePart("PART_EdgePointerForSource") as IEdgePointer;
_edgePointerForTarget = GetTemplatePart("PART_EdgePointerForTarget") as IEdgePointer;
SelfLoopedEdgeElement = GetTemplatePart("PART_SelfLoopedEdge") as FrameworkElement;
if(SelfLoopedEdgeElement != null)
SelfLoopedEdgeElement.LayoutUpdated += (sender, args) =>
SelfLoopIndicator = GetTemplatePart("PART_SelfLoopedEdge") as FrameworkElement;
if(SelfLoopIndicator != null)
SelfLoopIndicator.LayoutUpdated += (sender, args) =>
{
if (SelfLoopedEdgeElement != null) SelfLoopedEdgeElement.Arrange(_selfLoopedEdgeLastKnownRect);
if (SelfLoopIndicator != null) SelfLoopIndicator.Arrange(_selfLoopedEdgeLastKnownRect);
};
MeasureChild(_edgePointerForSource as UIElement);
MeasureChild(_edgePointerForTarget as UIElement);
MeasureChild(SelfLoopedEdgeElement);
MeasureChild(SelfLoopIndicator);
//TODO measure label?
UpdateSelfLoopedEdgeData();
@ -515,7 +556,7 @@ namespace GraphX.Controls
/// <summary>
///Gets is looped edge indicator template available. Used to pass some heavy cycle checks.
/// </summary>
protected bool HasSelfLoopedEdgeTemplate { get { return SelfLoopedEdgeElement != null; } }
protected bool HasSelfLoopedEdgeTemplate { get { return SelfLoopIndicator != null; } }
/// <summary>
/// Update SLE data such as template, edge pointers visibility
@ -530,12 +571,12 @@ namespace GraphX.Controls
if (_edgePointerForTarget != null) _edgePointerForTarget.Hide();
//return if we don't need to show edge loops
if (!RootArea.EdgeShowSelfLooped) return;
if (!ShowSelfLoopIndicator) return;
//pregenerate built-in indicator geometry if template PART is absent
if (!HasSelfLoopedEdgeTemplate)
_linegeometry = new EllipseGeometry();
else SelfLoopedEdgeElement.Visibility = Visibility.Visible;
else SelfLoopIndicator.Visibility = Visibility.Visible;
}
else
{
@ -543,7 +584,7 @@ namespace GraphX.Controls
if (_edgePointerForTarget != null && ShowArrows) _edgePointerForTarget.Show();
if (HasSelfLoopedEdgeTemplate)
SelfLoopedEdgeElement.Visibility = Visibility.Collapsed;
SelfLoopIndicator.Visibility = Visibility.Collapsed;
}
}
@ -619,27 +660,27 @@ namespace GraphX.Controls
{
#region Process self looped edges
if (!RootArea.EdgeShowSelfLooped)
if (!ShowSelfLoopIndicator)
return;
var hasNoTemplate = !HasSelfLoopedEdgeTemplate;
var pt =
new Point(
sourcePos1.X + RootArea.EdgeSelfLoopElementOffset.X - (hasNoTemplate ? RootArea.EdgeSelfLoopElementRadius : SelfLoopedEdgeElement.DesiredSize.Width),
sourcePos1.Y + RootArea.EdgeSelfLoopElementOffset.X - (hasNoTemplate ? RootArea.EdgeSelfLoopElementRadius : SelfLoopedEdgeElement.DesiredSize.Height));
sourcePos1.X + SelfLoopIndicatorOffset.X - (hasNoTemplate ? SelfLoopIndicatorRadius : SelfLoopIndicator.DesiredSize.Width),
sourcePos1.Y + SelfLoopIndicatorOffset.X - (hasNoTemplate ? SelfLoopIndicatorRadius : SelfLoopIndicator.DesiredSize.Height));
//if we has no self looped edge template defined we'll use default built-in indicator
if (hasNoTemplate)
{
var geometry = _linegeometry as EllipseGeometry;
geometry.Center = pt;
geometry.RadiusX = RootArea.EdgeSelfLoopElementRadius;
geometry.RadiusY = RootArea.EdgeSelfLoopElementRadius;
geometry.RadiusX = SelfLoopIndicatorRadius;
geometry.RadiusY = SelfLoopIndicatorRadius;
}
else
{
_selfLoopedEdgeLastKnownRect = new SysRect(pt, SelfLoopedEdgeElement.DesiredSize);
//SelfLoopedEdgeElement.Arrange(_selfLoopedEdgeLastKnownRect);
_selfLoopedEdgeLastKnownRect = new SysRect(pt, SelfLoopIndicator.DesiredSize);
//SelfLoopIndicator.Arrange(_selfLoopedEdgeLastKnownRect);
}
return;

Просмотреть файл

@ -108,22 +108,10 @@ namespace GraphX.Controls
/// </summary>
internal override bool IsEdgeRoutingEnabled { get { return LogicCore != null && LogicCore.IsEdgeRoutingEnabled; } }
/// <summary>
/// Link to LogicCore. Gets self looped edge radius.
/// </summary>
internal override double EdgeSelfLoopElementRadius { get { return LogicCore == null ? 0 : LogicCore.EdgeSelfLoopElementRadius; } }
/// <summary>
/// Link to LogicCore. Gets if self looped edges are enabled.
/// </summary>
internal override bool EdgeShowSelfLooped { get { return LogicCore != null && LogicCore.EdgeShowSelfLooped; } }
/// <summary>
/// Link to LogicCore. Gets if parallel edges are enabled.
/// </summary>
internal override bool EnableParallelEdges { get { return LogicCore != null && LogicCore.EnableParallelEdges; } }
/// <summary>
/// Link to LogicCore. Gets looped edge offset.
/// </summary>
internal override Point EdgeSelfLoopElementOffset { get { return LogicCore == null ? new Point() : LogicCore.EdgeSelfLoopElementOffset.ToWindows(); } }
/// <summary>
/// Link to LogicCore. Gets if edge curving is used.
/// </summary>
internal override bool EdgeCurvingEnabled { get { return LogicCore != null && LogicCore.EdgeCurvingEnabled; } }

Просмотреть файл

@ -301,10 +301,7 @@ namespace GraphX
/* INTERNAL VARIABLES FOR CONTROLS INTEROPERABILITY */
internal abstract bool IsEdgeRoutingEnabled { get; }
internal abstract double EdgeSelfLoopElementRadius { get; }
internal abstract bool EdgeShowSelfLooped { get; }
internal abstract bool EnableParallelEdges { get; }
internal abstract Point EdgeSelfLoopElementOffset { get; }
internal abstract bool EdgeCurvingEnabled { get; }
internal abstract double EdgeCurvingTolerance { get; }

Просмотреть файл

@ -65,7 +65,7 @@ namespace GraphX.Controls
DragBehaviour.SetIsDragEnabled(this, false);
_linegeometry = null;
_linePathObject = null;
SelfLoopedEdgeElement = null;
SelfLoopIndicator = null;
if (_edgeLabelControl != null)
{
_edgeLabelControl.Dispose();

Просмотреть файл

@ -102,22 +102,10 @@ namespace GraphX.Controls
/// </summary>
internal override bool IsEdgeRoutingEnabled { get { return LogicCore != null && LogicCore.IsEdgeRoutingEnabled; } }
/// <summary>
/// Link to LogicCore. Gets self looped edge radius.
/// </summary>
internal override double EdgeSelfLoopElementRadius { get { return LogicCore == null ? 0 : LogicCore.EdgeSelfLoopElementRadius; } }
/// <summary>
/// Link to LogicCore. Gets if self looped edges are enabled.
/// </summary>
internal override bool EdgeShowSelfLooped { get { return LogicCore != null && LogicCore.EdgeShowSelfLooped; } }
/// <summary>
/// Link to LogicCore. Gets if parallel edges are enabled.
/// </summary>
internal override bool EnableParallelEdges { get { return LogicCore != null && LogicCore.EnableParallelEdges; } }
/// <summary>
/// Link to LogicCore. Gets looped edge offset.
/// </summary>
internal override Point EdgeSelfLoopElementOffset { get { return LogicCore == null ? new Point() : LogicCore.EdgeSelfLoopElementOffset.ToWindows(); } }
/// <summary>
/// Link to LogicCore. Gets if edge curving is used.
/// </summary>
internal override bool EdgeCurvingEnabled { get { return LogicCore != null && LogicCore.EdgeCurvingEnabled; } }

Просмотреть файл

@ -390,10 +390,7 @@ namespace GraphX.Controls
/* INTERNAL VARIABLES FOR CONTROLS INTEROPERABILITY */
internal abstract bool IsEdgeRoutingEnabled { get; }
internal abstract double EdgeSelfLoopElementRadius { get; }
internal abstract bool EdgeShowSelfLooped { get; }
internal abstract bool EnableParallelEdges { get; }
internal abstract Point EdgeSelfLoopElementOffset { get; }
internal abstract bool EdgeCurvingEnabled { get; }
internal abstract double EdgeCurvingTolerance { get; }

Просмотреть файл

@ -19,18 +19,7 @@ namespace GraphX.PCL.Common.Interfaces
bool EdgeCurvingEnabled { get; set; }
double EdgeCurvingTolerance { get; set; }
/// <summary>
/// Gets or sets looped edge default indicator (path circle) radius
/// </summary>
double EdgeSelfLoopElementRadius { get; set; }
/// <summary>
/// Gets or sets looped edge offset form top-left vertex corner
/// </summary>
Point EdgeSelfLoopElementOffset { get; set; }
/// <summary>
/// Gets or sets if self looped edge indicators are visible
/// </summary>
bool EdgeShowSelfLooped { get; set; }
bool EnableParallelEdges { get; set; }
int ParallelEdgeDistance { get; set; }
bool IsEdgeRoutingEnabled { get; }

Просмотреть файл

@ -46,7 +46,7 @@ namespace GraphX.PCL.Logic.Models
public bool EnableEdgeLabelsOverlapRemoval { get; set; }
/// <summary>
/// Gets is custom layout selected and used
/// Gets is custom (NOT external) layout selected and used
/// </summary>
public bool IsCustomLayout { get { return DefaultLayoutAlgorithm == LayoutAlgorithmTypeEnum.Custom && ExternalLayoutAlgorithm == null; } }
@ -112,21 +112,6 @@ namespace GraphX.PCL.Logic.Models
/// </summary>
public double EdgeCurvingTolerance { get; set; }
/// <summary>
/// Radius of a self-loop edge, which is drawn as a circle. Default is 20.
/// </summary>
public double EdgeSelfLoopElementRadius { get; set; }
/// <summary>
/// Offset from the corner of the vertex. Useful for custom vertex shapes. Default is 10,10.
/// </summary>
public Point EdgeSelfLoopElementOffset { get; set; }
/// <summary>
/// Show self looped edges on vertices. Default value is true.
/// </summary>
public bool EdgeShowSelfLooped { get; set; }
/// <summary>
/// Main graph object
/// </summary>
@ -162,10 +147,7 @@ namespace GraphX.PCL.Logic.Models
CreateNewAlgorithmFactory();
CreateNewAlgorithmStorage(null, null, null);
Graph = graph;
EdgeSelfLoopElementOffset = new Point();
EdgeCurvingTolerance = 8;
EdgeSelfLoopElementRadius = 5;
EdgeShowSelfLooped = true;
ParallelEdgeDistance = 5;
}