зеркало из https://github.com/stride3d/GraphX.git
Edge Drag (#75)
* + SetEdgesDrag * + Edge가 Drag 가능하도록 설정 * + Edge Drag * Fix * + PrepareEdgePathFromMousePointer Target Position Edit
This commit is contained in:
Родитель
23ca31e797
Коммит
0f2eb18e49
|
@ -289,6 +289,7 @@ namespace ShowcaseApp.WPF.Pages
|
|||
|
||||
erg_Area.GenerateGraph(gr, true);
|
||||
erg_Area.SetVerticesDrag(true, true);
|
||||
erg_Area.SetEdgesDrag(true);
|
||||
erg_zoomctrl.ZoomToFill();
|
||||
|
||||
return;
|
||||
|
|
|
@ -138,6 +138,7 @@ namespace ShowcaseApp.WPF.Pages
|
|||
_opMode = EditorOperationMode.Select;
|
||||
ClearEditMode();
|
||||
graphArea.SetVerticesDrag(true, true);
|
||||
graphArea.SetEdgesDrag(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace ShowcaseApp.WPF.Pages
|
|||
gg_Area.RelayoutFinished += gg_Area_RelayoutFinished;
|
||||
gg_Area.GenerateGraphFinished += gg_Area_GenerateGraphFinished;
|
||||
gg_Area.VertexLabelFactory = new DefaultVertexlabelFactory();
|
||||
gg_Area.SetEdgesDrag(true);
|
||||
|
||||
ggLogic.DefaultEdgeRoutingAlgorithm = EdgeRoutingAlgorithmTypeEnum.SimpleER;
|
||||
ggLogic.EdgeCurvingEnabled = true;
|
||||
|
|
|
@ -1,63 +1,73 @@
|
|||
<UserControl x:Class="ShowcaseApp.WPF.Pages.Mini.LayoutVCP"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:wpf="clr-namespace:ShowcaseApp.WPF"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/"
|
||||
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:ShowcaseApp.WPF.Models"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="600">
|
||||
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
|
||||
xmlns:wpf="clr-namespace:ShowcaseApp.WPF"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="600"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Templates/MiniFeatures.xaml"/>
|
||||
<ResourceDictionary Source="/Templates/Mini/LayoutVCPTemplate.xaml"/>
|
||||
<ResourceDictionary Source="/Templates/MiniFeatures.xaml" />
|
||||
<ResourceDictionary Source="/Templates/Mini/LayoutVCPTemplate.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
|
||||
</Grid.Resources>
|
||||
|
||||
<Border BorderBrush="{DynamicResource ButtonBorder}" BorderThickness="1" Margin="2" >
|
||||
<controls:ZoomControl x:Name="zoomControl" Background="{DynamicResource ButtonBackground}" Foreground="{DynamicResource ButtonText}" HorizontalContentAlignment="Center" VerticalAlignment="Center">
|
||||
<wpf:GraphAreaExample x:Name="graphArea"/>
|
||||
|
||||
<Border Margin="2"
|
||||
BorderBrush="{DynamicResource ButtonBorder}"
|
||||
BorderThickness="1">
|
||||
<controls:ZoomControl x:Name="zoomControl"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
Background="{DynamicResource ButtonBackground}"
|
||||
Foreground="{DynamicResource ButtonText}">
|
||||
<wpf:GraphAreaExample x:Name="graphArea" />
|
||||
</controls:ZoomControl>
|
||||
</Border>
|
||||
|
||||
<Expander VerticalAlignment="Bottom"
|
||||
Margin="2"
|
||||
IsExpanded="false"
|
||||
ExpandDirection="Down"
|
||||
Header="SETTINGS"
|
||||
Template="{DynamicResource MiniExpander}"
|
||||
Padding="5">
|
||||
|
||||
<StackPanel Orientation="Vertical" MinHeight="50" VerticalAlignment="Center"
|
||||
Margin="10">
|
||||
<CheckBox Height="25"
|
||||
Name="cbMathShape"
|
||||
IsChecked="True"
|
||||
Content ="Use math shape for connector"
|
||||
ToolTip="If math shape is specified an edge will connect to the point around some math shape. If not it will simply point to connector center."
|
||||
/>
|
||||
<Button Content="Add VCP from runtime" Margin="2" Name="butAddVcp" HorizontalAlignment="Left"/>
|
||||
<Expander Margin="2"
|
||||
VerticalAlignment="Bottom"
|
||||
ExpandDirection="Down"
|
||||
Header="SETTINGS"
|
||||
IsExpanded="false"
|
||||
Padding="5"
|
||||
Template="{DynamicResource MiniExpander}">
|
||||
|
||||
<StackPanel MinHeight="50"
|
||||
Margin="10"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical">
|
||||
<CheckBox Name="cbMathShape"
|
||||
Height="25"
|
||||
Content="Use math shape for connector"
|
||||
IsChecked="True"
|
||||
ToolTip="If math shape is specified an edge will connect to the point around some math shape. If not it will simply point to connector center." />
|
||||
<Button Name="butAddVcp"
|
||||
Margin="2"
|
||||
HorizontalAlignment="Left"
|
||||
Content="Add VCP from runtime" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<Border HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
<Border Margin="0,2,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Background="{DynamicResource WindowBackground}"
|
||||
BorderBrush="{DynamicResource ButtonBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="0,0,0,15"
|
||||
Margin="0,2,2,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<mui:ModernButton Style="{DynamicResource MainControlButtonHelp}"
|
||||
Command="models:LinkCommands.ShowMiniSpecialDialog"
|
||||
BorderBrush="{DynamicResource ButtonBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="0,0,0,15">
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<mui:ModernButton Command="models:LinkCommands.ShowMiniSpecialDialog"
|
||||
CommandParameter="{x:Static models:MiniSpecialType.LayoutVCP}"
|
||||
/>
|
||||
Style="{DynamicResource MainControlButtonHelp}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace ShowcaseApp.WPF.Pages.Mini
|
|||
private void CbMathShapeOnChecked(object sender, RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
foreach(var item in graphArea.VertexList.Values)
|
||||
item.VertexConnectionPointsList.ForEach(a => a.Shape = cbMathShape.IsChecked == true ? VertexShape.Circle : VertexShape.None);
|
||||
item.VertexConnectionPointsList.ForEach(a => a.Shape = cbMathShape.IsChecked == true ? VertexShape.Circle : VertexShape.None);
|
||||
graphArea.UpdateAllEdges(true);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ namespace ShowcaseApp.WPF.Pages.Mini
|
|||
ShowcaseHelper.AddEdge(logicCore.Graph, vList[5], vList[2], 2, 3);
|
||||
|
||||
graphArea.LogicCore = logicCore;
|
||||
//set positions
|
||||
//set positions
|
||||
var posList = new Dictionary<DataVertex, Point>()
|
||||
{
|
||||
{vList[0], new Point(0, 0)},
|
||||
|
@ -99,6 +99,7 @@ namespace ShowcaseApp.WPF.Pages.Mini
|
|||
|
||||
//settings
|
||||
graphArea.SetVerticesDrag(true, true);
|
||||
graphArea.SetEdgesDrag(true);
|
||||
|
||||
zoomControl.ZoomToFill();
|
||||
}
|
||||
|
|
|
@ -1,42 +1,53 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/">
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/">
|
||||
|
||||
<!--<Style TargetType="{x:Type local:GraphAreaExample}">
|
||||
<Setter Property="Background" Value="LightGray"/>
|
||||
</Style>-->
|
||||
</Style>-->
|
||||
|
||||
<Style TargetType="controls:StaticVertexConnectionPoint" x:Shared="False">
|
||||
<Setter Property="Shape" Value="Circle"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Style x:Shared="False" TargetType="controls:StaticVertexConnectionPoint">
|
||||
<Setter Property="Shape" Value="Circle" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Content">
|
||||
<Setter.Value>
|
||||
<Path Stroke="Black" Data="M 38,0.791664C 58.5496,0.791664 75.2083,17.4504 75.2083,38C 75.2083,58.5496 58.5496,75.2083 38,75.2083C 17.4504,75.2083 0.791662,58.5496 0.791662,38C 0.791662,17.4504 17.4504,0.791664 38,0.791664 Z M 38,5.54166C 20.0738,5.54166 5.54167,20.0738 5.54167,38C 5.54167,55.9262 20.0738,70.4583 38,70.4583C 55.9262,70.4583 70.4583,55.9262 70.4583,38C 70.4583,20.0738 55.9262,5.54166 38,5.54166 Z "
|
||||
Width="10" Height="10" Stretch="Uniform" StrokeThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 38,0.791664C 58.5496,0.791664 75.2083,17.4504 75.2083,38C 75.2083,58.5496 58.5496,75.2083 38,75.2083C 17.4504,75.2083 0.791662,58.5496 0.791662,38C 0.791662,17.4504 17.4504,0.791664 38,0.791664 Z M 38,5.54166C 20.0738,5.54166 5.54167,20.0738 5.54167,38C 5.54167,55.9262 20.0738,70.4583 38,70.4583C 55.9262,70.4583 70.4583,55.9262 70.4583,38C 70.4583,20.0738 55.9262,5.54166 38,5.54166 Z "
|
||||
Stretch="Uniform"
|
||||
Stroke="Black"
|
||||
StrokeThickness="1" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
|
||||
|
||||
<Style TargetType="{x:Type controls:VertexControl}">
|
||||
<Setter Property="Background" Value="Yellow"/>
|
||||
<Setter Property="Background" Value="Yellow" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Name="bb" Background="{TemplateBinding Background}" Grid.Column="1"
|
||||
BorderBrush="{TemplateBinding BorderBrush}" Width="20" Height="20" BorderThickness="1">
|
||||
</Border>
|
||||
<StackPanel Orientation="Vertical" Grid.Column="0" Name="PART_vcproot">
|
||||
<Border Padding="0" Margin="2,2,0,2">
|
||||
<controls:StaticVertexConnectionPoint Id="1"/>
|
||||
<StackPanel Name="PART_vcproot"
|
||||
Grid.Column="0"
|
||||
Orientation="Vertical">
|
||||
<Border Margin="2,2,0,2" Padding="0">
|
||||
<controls:StaticVertexConnectionPoint Id="1" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<Border Name="bb"
|
||||
Grid.Column="1"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
|
@ -44,11 +55,13 @@
|
|||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsBlue}" Value="True">
|
||||
<DataTrigger.Setters>
|
||||
<Setter Property="Background" Value="Blue"/>
|
||||
<Setter Property="Background" Value="Blue" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
|
||||
<Ellipse Width="50" Height="50" Fill="{TemplateBinding Background}"/>
|
||||
<Ellipse Width="50"
|
||||
Height="50"
|
||||
Fill="{TemplateBinding Background}" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
@ -59,71 +72,89 @@
|
|||
|
||||
|
||||
<controls:VisibilityToBoolConverter x:Key="VisibilityToBoolConverter" Inverted="True" />
|
||||
<controls:VisibilityToBoolConverter x:Key="VisibilityToBoolConverterNot" Inverted="True" Not="True"/>
|
||||
|
||||
<controls:VisibilityToBoolConverter x:Key="VisibilityToBoolConverterNot"
|
||||
Inverted="True"
|
||||
Not="True" />
|
||||
|
||||
<Style TargetType="{x:Type controls:EdgeControl}">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:EdgeControl}">
|
||||
<Grid>
|
||||
<Path Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1"
|
||||
x:Name="PART_edgePath"/>
|
||||
<controls:DefaultEdgePointer NeedRotation="true" x:Name="PART_EdgePointerForSource" Visibility="{Binding ArrowTarget, Converter={StaticResource VisibilityToBoolConverterNot}}">
|
||||
<Path Data="M0,0.5 L1,1 1,0" Fill="Black" Stretch="Uniform" Width="7" Height="7" />
|
||||
<Path x:Name="PART_edgePath"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1" />
|
||||
<controls:DefaultEdgePointer x:Name="PART_EdgePointerForSource"
|
||||
NeedRotation="true"
|
||||
Visibility="{Binding ArrowTarget,
|
||||
Converter={StaticResource VisibilityToBoolConverterNot}}">
|
||||
<Path Width="7"
|
||||
Height="7"
|
||||
Data="M0,0.5 L1,1 1,0"
|
||||
Fill="Black"
|
||||
Stretch="Uniform" />
|
||||
</controls:DefaultEdgePointer>
|
||||
<controls:DefaultEdgePointer NeedRotation="true" x:Name="PART_EdgePointerForTarget" Visibility="{Binding ArrowTarget, Converter={StaticResource VisibilityToBoolConverter}}">
|
||||
<Path Data="M0,0.5 L1,1 1,0" Fill="Black" Stretch="Uniform" Width="7" Height="7"/>
|
||||
<controls:DefaultEdgePointer x:Name="PART_EdgePointerForTarget"
|
||||
NeedRotation="true"
|
||||
Visibility="{Binding ArrowTarget,
|
||||
Converter={StaticResource VisibilityToBoolConverter}}">
|
||||
<Path Width="7"
|
||||
Height="7"
|
||||
Data="M0,0.5 L1,1 1,0"
|
||||
Fill="Black"
|
||||
Stretch="Uniform" />
|
||||
</controls: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 "/>
|
||||
-->
|
||||
<!-- <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 "/> -->
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- REGION EDGE LABLE CONTROL -->
|
||||
<!-- REGION EDGE LABLE CONTROL -->
|
||||
<Style TargetType="{x:Type controls:EdgeLabelControl}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:EdgeLabelControl}">
|
||||
<Grid>
|
||||
<Border BorderBrush="Black" BorderThickness="1" Background="White" CornerRadius="8">
|
||||
<ContentPresenter Margin="3"/>
|
||||
<Border Background="White"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ContentPresenter Margin="3" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Setter Property="DisplayForSelfLoopedEdges" Value="False"/>
|
||||
<Setter Property="DisplayForSelfLoopedEdges" Value="False" />
|
||||
</Style>
|
||||
<!-- ENDREGION -->
|
||||
<!-- ENDREGION -->
|
||||
|
||||
<!-- REGION VERTEX LABEL CONTROL -->
|
||||
<!-- REGION VERTEX LABEL CONTROL -->
|
||||
<Style TargetType="controls:VertexLabelControl">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="LabelPositionMode" Value="Sides"/>
|
||||
<Setter Property="LabelPositionSide" Value="BottomRight"/>
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
<Setter Property="LabelPositionMode" Value="Sides" />
|
||||
<Setter Property="LabelPositionSide" Value="BottomRight" />
|
||||
|
||||
<!-- Custom label template body -->
|
||||
<!-- Custom label template body -->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:VertexLabelControl">
|
||||
<Grid>
|
||||
<ContentPresenter Margin="3"/>
|
||||
<ContentPresenter Margin="3" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<!-- ENDREGION -->
|
||||
<!-- ENDREGION -->
|
||||
</ResourceDictionary>
|
|
@ -1,65 +1,76 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:ShowcaseApp.WPF"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/">
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/"
|
||||
xmlns:local="clr-namespace:ShowcaseApp.WPF">
|
||||
|
||||
<local:ValueToImageConverter x:Key="ValueToImage"/>
|
||||
|
||||
<!-- VERTEX CONTROL -->
|
||||
<local:ValueToImageConverter x:Key="ValueToImage" />
|
||||
|
||||
<!-- VERTEX CONTROL -->
|
||||
<Style TargetType="{x:Type controls:VertexControl}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="VertexShape" Value="Circle"/>
|
||||
<Setter Property="ShowLabel" Value="True"/>
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="VertexShape" Value="Circle" />
|
||||
<Setter Property="ShowLabel" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
|
||||
|
||||
<Grid>
|
||||
<Image Source="{Binding ImageId, Converter={StaticResource ValueToImage}}" Margin="0" Width="80" Stretch="UniformToFill"/>
|
||||
<Image Width="80"
|
||||
Margin="0"
|
||||
Source="{Binding ImageId,
|
||||
Converter={StaticResource ValueToImage}}"
|
||||
Stretch="UniformToFill" />
|
||||
<!-- removed in favor of new attachable vertex label logic
|
||||
<controls:VertexLabelControl x:Name="PART_vertexLabel" Content="{Binding Vertex.Text, RelativeSource={RelativeSource TemplatedParent}}" LabelPositionSide="Bottom" />-->
|
||||
</Grid>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<!-- VERTEX DRAGGING CONTROL -->
|
||||
<Setter Property="controls:DragBehaviour.IsDragEnabled"
|
||||
Value="True" />
|
||||
<Setter Property="controls:DragBehaviour.UpdateEdgesOnMove"
|
||||
Value="True" />
|
||||
<!-- VERTEX DRAGGING CONTROL -->
|
||||
<Setter Property="controls:DragBehaviour.IsDragEnabled" Value="True" />
|
||||
<Setter Property="controls:DragBehaviour.UpdateEdgesOnMove" Value="True" />
|
||||
</Style>
|
||||
|
||||
<controls:VisibilityToBoolConverter Inverted="True" Not="True" x:Key="BooleanToVisibility"/>
|
||||
<controls:VisibilityToBoolConverter x:Key="BooleanToVisibility"
|
||||
Inverted="True"
|
||||
Not="True" />
|
||||
|
||||
<!-- EDGE CONTROL -->
|
||||
<!-- EDGE CONTROL -->
|
||||
<Style TargetType="{x:Type controls:EdgeControl}">
|
||||
<Setter Property="SelfLoopIndicatorOffset" Value="10,10"/>
|
||||
<Setter Property="SelfLoopIndicatorOffset" Value="10,10" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:EdgeControl}">
|
||||
<Grid>
|
||||
<Path Stroke="#FF976969"
|
||||
<Path x:Name="PART_edgePath"
|
||||
Stroke="#FF976969"
|
||||
StrokeThickness="3"
|
||||
ToolTip="{TemplateBinding ToolTip}"
|
||||
x:Name="PART_edgePath"/>
|
||||
<controls:DefaultEdgePointer NeedRotation="true" x:Name="PART_EdgePointerForTarget" >
|
||||
<Path Data="M0,0.5 L1,1 1,0" Fill="Black" Stretch="Uniform" Width="15" Height="15"/>
|
||||
ToolTip="{TemplateBinding ToolTip}" />
|
||||
<controls:DefaultEdgePointer x:Name="PART_EdgePointerForTarget" NeedRotation="true">
|
||||
<Path Width="15"
|
||||
Height="15"
|
||||
Data="M0,0.5 L1,1 1,0"
|
||||
Fill="Black"
|
||||
Stretch="Uniform" />
|
||||
</controls:DefaultEdgePointer>
|
||||
<Path x:Name="PART_SelfLoopedEdge"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Stretch="Uniform"
|
||||
Fill="Black"
|
||||
<controls:DefaultEdgePointer x:Name="PART_EdgePointerForSource" NeedRotation="true">
|
||||
<Path Width="15"
|
||||
Height="15"
|
||||
Data="M2,0.5 L1,1 1,0"
|
||||
Fill="Red"
|
||||
Stretch="Uniform" />
|
||||
</controls:DefaultEdgePointer>
|
||||
<Path x:Name="PART_SelfLoopedEdge"
|
||||
Width="10"
|
||||
Height="10"
|
||||
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 "
|
||||
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 "/>
|
||||
Stretch="Uniform"
|
||||
ToolTip="This vertex has some self looped edges!" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
|
@ -1,47 +1,61 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/"
|
||||
>
|
||||
xmlns:controls="http://schemas.panthernet.ru/graphx/">
|
||||
|
||||
<Style TargetType="controls:StaticVertexConnectionPoint" x:Shared="False">
|
||||
<Setter Property="Shape" Value="Circle"/>
|
||||
<Style x:Shared="False" TargetType="controls:StaticVertexConnectionPoint">
|
||||
<Setter Property="Shape" Value="Circle" />
|
||||
|
||||
<Setter Property="Content">
|
||||
<Setter.Value>
|
||||
<Path Stroke="{DynamicResource ButtonText}" Data="M 38,0.791664C 58.5496,0.791664 75.2083,17.4504 75.2083,38C 75.2083,58.5496 58.5496,75.2083 38,75.2083C 17.4504,75.2083 0.791662,58.5496 0.791662,38C 0.791662,17.4504 17.4504,0.791664 38,0.791664 Z M 38,5.54166C 20.0738,5.54166 5.54167,20.0738 5.54167,38C 5.54167,55.9262 20.0738,70.4583 38,70.4583C 55.9262,70.4583 70.4583,55.9262 70.4583,38C 70.4583,20.0738 55.9262,5.54166 38,5.54166 Z "
|
||||
Width="10" Height="10" Stretch="Uniform" StrokeThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 38,0.791664C 58.5496,0.791664 75.2083,17.4504 75.2083,38C 75.2083,58.5496 58.5496,75.2083 38,75.2083C 17.4504,75.2083 0.791662,58.5496 0.791662,38C 0.791662,17.4504 17.4504,0.791664 38,0.791664 Z M 38,5.54166C 20.0738,5.54166 5.54167,20.0738 5.54167,38C 5.54167,55.9262 20.0738,70.4583 38,70.4583C 55.9262,70.4583 70.4583,55.9262 70.4583,38C 70.4583,20.0738 55.9262,5.54166 38,5.54166 Z "
|
||||
Stretch="Uniform"
|
||||
Stroke="{DynamicResource ButtonText}"
|
||||
StrokeThickness="1" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<Style TargetType="{x:Type controls:VertexControl}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonText}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonText}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border BorderThickness="1" BorderBrush="{TemplateBinding Foreground}" Background="{DynamicResource ButtonBackgroundPressed}" Grid.Column="1" CornerRadius="5" Width="120">
|
||||
<ContentPresenter Content="{TemplateBinding Vertex}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<StackPanel Name="PART_vcproot"
|
||||
Grid.Column="0"
|
||||
Orientation="Vertical">
|
||||
<Border Margin="2,2,0,2" Padding="0">
|
||||
<controls:StaticVertexConnectionPoint Id="1" />
|
||||
</Border>
|
||||
<Border Margin="2,2,0,2" Padding="0">
|
||||
<controls:StaticVertexConnectionPoint Id="2" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<Border Grid.Column="1"
|
||||
Width="120"
|
||||
Background="{DynamicResource ButtonBackgroundPressed}"
|
||||
BorderBrush="{TemplateBinding Foreground}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Vertex}" />
|
||||
</Border>
|
||||
<StackPanel Orientation="Vertical" Grid.Column="0" Name="PART_vcproot">
|
||||
<Border Padding="0" Margin="2,2,0,2">
|
||||
<controls:StaticVertexConnectionPoint Id="1"/>
|
||||
<StackPanel Grid.Column="2" Orientation="Vertical">
|
||||
<Border Margin="0,2,2,2" Padding="0">
|
||||
<controls:StaticVertexConnectionPoint Id="3" />
|
||||
</Border>
|
||||
<Border Padding="0" Margin="2,2,0,2">
|
||||
<controls:StaticVertexConnectionPoint Id="2"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Grid.Column="2">
|
||||
<Border Padding="0" Margin="0,2,2,2">
|
||||
<controls:StaticVertexConnectionPoint Id="3"/>
|
||||
</Border>
|
||||
<Border Padding="0" Margin="0,2,2,2">
|
||||
<controls:StaticVertexConnectionPoint Id="4"/>
|
||||
<Border Margin="0,2,2,2" Padding="0">
|
||||
<controls:StaticVertexConnectionPoint Id="4" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
@ -51,16 +65,20 @@
|
|||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type controls:EdgeControl}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonText}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonText}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:EdgeControl}">
|
||||
<Grid>
|
||||
<Path Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="2"
|
||||
x:Name="PART_edgePath"/>
|
||||
<controls:DefaultEdgePointer NeedRotation="true" x:Name="PART_EdgePointerForTarget" >
|
||||
<Path Data="M0,0.5 L1,1 1,0" Fill="{TemplateBinding Foreground}" Stretch="Uniform" Width="10" Height="10"/>
|
||||
<Path x:Name="PART_edgePath"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="2" />
|
||||
<controls:DefaultEdgePointer x:Name="PART_EdgePointerForTarget" NeedRotation="true">
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
Data="M0,0.5 L1,1 1,0"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
Stretch="Uniform" />
|
||||
</controls:DefaultEdgePointer>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
|
|
@ -1,46 +1,52 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
#if WPF
|
||||
|
||||
using System.Windows;
|
||||
|
||||
#elif METRO
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.Foundation;
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
using GraphX.PCL.Common.Exceptions;
|
||||
using GraphX.PCL.Common.Interfaces;
|
||||
using GraphX.PCL.Common.Models;
|
||||
|
||||
namespace GraphX.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Dragging behavior of objects in a GraphX graph area is influenced using the attached properties of this class.
|
||||
///
|
||||
///
|
||||
/// To enable dragging of an individual object, set the IsDragEnabled attached property to true on that object. When IsDragEnabled is true, the
|
||||
/// object can be used to initiate dragging.
|
||||
///
|
||||
///
|
||||
/// To drag a group of vertices, set the IsTagged attached property to true for all of the vertices in the group. When dragging is started from
|
||||
/// one of the tagged vertices, all of the tagged ones will be move.
|
||||
///
|
||||
///
|
||||
/// "Primary drag object" defined: Whichever object gets the mouse/pointer events is treated as the primary drag object and its attached properties take
|
||||
/// precedence for controlling drag behavior. When only one object is being dragged, it is the primary drag object. When a group of objects is tagged
|
||||
/// and being dragged together, the one getting mouse events is the primary drag object.
|
||||
///
|
||||
///
|
||||
/// There is limited support for dragging edges. It is achieved by setting IsDragEnabled to true for the edge AND tagging the edge and the vertices
|
||||
/// it is attached to. When the user drags the edge, the drag is actually performed on the vertices.
|
||||
///
|
||||
///
|
||||
/// For edges to be updated as a vertex is moved, set UpdateEdgesOnMove to true for the object being dragged.
|
||||
///
|
||||
///
|
||||
/// Snapping is turned on or off by the GlobalIsSnappingPredicate or by the IsSnappingPredicate property on the primary drag object. The predicate is
|
||||
/// called with each movement of the mouse/pointer and the primary drag object is passed in. If snapping should be performed, the predicate must return
|
||||
/// true. To skip snapping logic, the predicate must return false. If no predicate is set using the IsSnappingPredicate, the GlobalIsSnappingPredicate
|
||||
/// is used. The default behavior is to snap while a shift key alone is pressed.
|
||||
///
|
||||
///
|
||||
/// When dragging a group of objects and using snapping, there is an additional refinement that can be used for the snapping behavior of the individual
|
||||
/// objects in the group. The individual objects can move the exact same amount as the primary object when it snaps, or they can snap individually, with
|
||||
/// the snap calculation being performed for each one. The behavior is controlled for the entire group by the GlobalIsSnappingIndividuallyPredicate or
|
||||
/// the IsIndividualSnappingPredicate property setting ON THE PRIMARY DRAG OBJECT. The default behavior is to move all dragged objects by the same offset
|
||||
/// as the primary drag object.
|
||||
///
|
||||
///
|
||||
/// Snapping calculations are performed by the functions set on the primary drag object using the GlobalXSnapModifier or XSnapModifier property and the
|
||||
/// GlobalYSnapModifier or YSnapModifier propery. These functions are called for each movement and provided the GraphAreaBase, object being moved, and
|
||||
/// the pre-snapped x or y value. The passed in parameters are intended to provide an opportunity to find elements within the graph area and do things
|
||||
|
@ -65,7 +71,7 @@ namespace GraphX.Controls
|
|||
|
||||
private static readonly SnapModifierFunc _builtinSnapModifier = (area, obj, val) => Math.Round(val * 0.1) * 10.0;
|
||||
|
||||
#endregion
|
||||
#endregion Built-in snapping behavior
|
||||
|
||||
#region Global snapping behavior management
|
||||
|
||||
|
@ -94,7 +100,6 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static Predicate<DependencyObject> _globalIsIndividualSnappingPredicate = _builtinIsIndividualSnappingPredicate;
|
||||
|
||||
/// <summary>
|
||||
|
@ -171,19 +176,22 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Global snapping behavior management
|
||||
|
||||
#region Attached DPs
|
||||
|
||||
public static readonly DependencyProperty IsDragEnabledProperty = DependencyProperty.RegisterAttached("IsDragEnabled", typeof(bool), typeof(DragBehaviour), new PropertyMetadata(false, OnIsDragEnabledPropertyChanged));
|
||||
public static readonly DependencyProperty UpdateEdgesOnMoveProperty = DependencyProperty.RegisterAttached("UpdateEdgesOnMove", typeof(bool), typeof(DragBehaviour), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsTaggedProperty = DependencyProperty.RegisterAttached("IsTagged", typeof(bool), typeof(DragBehaviour), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(DragBehaviour), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsSnappingPredicateProperty = DependencyProperty.RegisterAttached("IsSnappingPredicate", typeof(Predicate<DependencyObject>), typeof(DragBehaviour), new PropertyMetadata(new Predicate<DependencyObject>(obj => { return _globalIsSnappingPredicate(obj); })));
|
||||
public static readonly DependencyProperty IsIndividualSnappingPredicateProperty = DependencyProperty.RegisterAttached("IsIndividualSnappingPredicate", typeof(Predicate<DependencyObject>), typeof(DragBehaviour), new PropertyMetadata(new Predicate<DependencyObject>(obj => { return _globalIsIndividualSnappingPredicate(obj); })));
|
||||
|
||||
/// <summary>
|
||||
/// Snap feature modifier delegate for X axis
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty XSnapModifierProperty = DependencyProperty.RegisterAttached("XSnapModifier", typeof(SnapModifierFunc), typeof(DragBehaviour), new PropertyMetadata(new SnapModifierFunc((area, obj, val) => _globalXSnapModifier(area, obj, val))));
|
||||
|
||||
/// <summary>
|
||||
/// Snap feature modifier delegate for Y axis
|
||||
/// </summary>
|
||||
|
@ -193,9 +201,11 @@ namespace GraphX.Controls
|
|||
private static readonly DependencyProperty OriginalYProperty = DependencyProperty.RegisterAttached("OriginalY", typeof(double), typeof(DragBehaviour), new PropertyMetadata(0.0));
|
||||
private static readonly DependencyProperty OriginalMouseXProperty = DependencyProperty.RegisterAttached("OriginalMouseX", typeof(double), typeof(DragBehaviour), new PropertyMetadata(0.0));
|
||||
private static readonly DependencyProperty OriginalMouseYProperty = DependencyProperty.RegisterAttached("OriginalMouseY", typeof(double), typeof(DragBehaviour), new PropertyMetadata(0.0));
|
||||
#endregion
|
||||
|
||||
#endregion Attached DPs
|
||||
|
||||
#region Get/Set method for Attached Properties
|
||||
|
||||
public static bool GetUpdateEdgesOnMove(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(UpdateEdgesOnMoveProperty);
|
||||
|
@ -276,7 +286,7 @@ namespace GraphX.Controls
|
|||
obj.SetValue(YSnapModifierProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Get/Set method for Attached Properties
|
||||
|
||||
#region Get/Set methods for private Attached Properties
|
||||
|
||||
|
@ -319,9 +329,11 @@ namespace GraphX.Controls
|
|||
{
|
||||
obj.SetValue(OriginalMouseYProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion Get/Set methods for private Attached Properties
|
||||
|
||||
#region PropertyChanged callbacks
|
||||
|
||||
private static void OnIsDragEnabledPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
#if WPF
|
||||
|
@ -341,8 +353,16 @@ namespace GraphX.Controls
|
|||
{
|
||||
//register the event handlers
|
||||
#if WPF
|
||||
element.MouseLeftButtonDown += OnDragStarted;
|
||||
element.PreviewMouseLeftButtonUp += OnDragFinished;
|
||||
if (element.GetType() == typeof(VertexControl))
|
||||
{
|
||||
element.MouseLeftButtonDown += OnVertexDragStarted;
|
||||
element.PreviewMouseLeftButtonUp += OnVertexDragFinished;
|
||||
}
|
||||
else if (element.GetType() == typeof(EdgeControl))
|
||||
{
|
||||
element.MouseLeftButtonDown += OnEdgeDrageStarted;
|
||||
element.PreviewMouseLeftButtonUp += OnEdgeDragFinished;
|
||||
}
|
||||
#elif METRO
|
||||
element.PointerPressed += OnDragStarted;
|
||||
element.PointerReleased += OnDragFinished;
|
||||
|
@ -352,18 +372,107 @@ namespace GraphX.Controls
|
|||
{
|
||||
//unregister the event handlers
|
||||
#if WPF
|
||||
element.MouseLeftButtonDown -= OnDragStarted;
|
||||
element.PreviewMouseLeftButtonUp -= OnDragFinished;
|
||||
if (element.GetType() == typeof(VertexControl))
|
||||
{
|
||||
element.MouseLeftButtonDown -= OnVertexDragStarted;
|
||||
element.PreviewMouseLeftButtonUp -= OnVertexDragFinished;
|
||||
}
|
||||
else if (element.GetType() == typeof(EdgeControl))
|
||||
{
|
||||
element.MouseLeftButtonDown -= OnEdgeDrageStarted;
|
||||
element.PreviewMouseLeftButtonUp -= OnEdgeDragFinished;
|
||||
}
|
||||
#elif METRO
|
||||
element.PointerPressed -= OnDragStarted;
|
||||
element.PointerReleased -= OnDragFinished;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion PropertyChanged callbacks
|
||||
|
||||
private static void OnEdgeDrageStarted(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
DependencyObject obj = sender as DependencyObject;
|
||||
|
||||
SetIsDragging(obj, true);
|
||||
|
||||
var element = obj as IInputElement;
|
||||
if (element != null)
|
||||
{
|
||||
element.CaptureMouse();
|
||||
element.MouseMove -= OnEdgeDragging;
|
||||
element.MouseMove += OnEdgeDragging;
|
||||
}
|
||||
else throw new GX_InvalidDataException("The control must be a descendent of the FrameworkElement or FrameworkContentElement!");
|
||||
|
||||
e.Handled = false;
|
||||
}
|
||||
|
||||
private static void OnEdgeDragging(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
var obj = sender as DependencyObject;
|
||||
if (!GetIsDragging(obj))
|
||||
return;
|
||||
|
||||
EdgeControl edgeControl = sender as EdgeControl;
|
||||
|
||||
edgeControl.PrepareEdgePathFromMousePointer();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private static void OnEdgeDragFinished(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
EdgeControl edgeControl = sender as EdgeControl;
|
||||
|
||||
if (edgeControl == null) return;
|
||||
|
||||
GraphAreaBase graphAreaBase = edgeControl.RootArea;
|
||||
|
||||
VertexControl vertexControl = graphAreaBase.GetVertexControlAt(e.GetPosition(graphAreaBase));
|
||||
|
||||
if (vertexControl != null)
|
||||
{
|
||||
edgeControl.Target = vertexControl;
|
||||
|
||||
if (vertexControl.VertexConnectionPointsList.Count > 0)
|
||||
{
|
||||
IVertexConnectionPoint vertexConnectionPoint = vertexControl.GetConnectionPointAt(e.GetPosition(graphAreaBase));
|
||||
|
||||
var edge = edgeControl.Edge as IGraphXCommonEdge;
|
||||
|
||||
if (vertexConnectionPoint != null)
|
||||
{
|
||||
edge.TargetConnectionPointId = vertexConnectionPoint.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.TargetConnectionPointId = null;
|
||||
}
|
||||
}
|
||||
|
||||
edgeControl.UpdateEdge();
|
||||
|
||||
var obj = (DependencyObject)sender;
|
||||
SetIsDragging(obj, false);
|
||||
//obj.ClearValue(OriginalMouseXProperty);
|
||||
//obj.ClearValue(OriginalMouseYProperty);
|
||||
//obj.ClearValue(OriginalXProperty);
|
||||
//obj.ClearValue(OriginalYProperty);
|
||||
|
||||
var element = sender as IInputElement;
|
||||
if (element != null)
|
||||
{
|
||||
element.MouseMove -= OnVertexDragging;
|
||||
element.ReleaseMouseCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WPF
|
||||
private static void OnDragStarted(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
|
||||
private static void OnVertexDragStarted(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
#elif METRO
|
||||
private static void OnDragStarted( object sender, PointerRoutedEventArgs e )
|
||||
#endif
|
||||
|
@ -399,8 +508,8 @@ namespace GraphX.Controls
|
|||
if (element != null)
|
||||
{
|
||||
element.CaptureMouse();
|
||||
element.MouseMove -= OnDragging;
|
||||
element.MouseMove += OnDragging;
|
||||
element.MouseMove -= OnVertexDragging;
|
||||
element.MouseMove += OnVertexDragging;
|
||||
}
|
||||
//else throw new GX_InvalidDataException("The control must be a descendent of the FrameworkElement or FrameworkContentElement!");
|
||||
e.Handled = false;
|
||||
|
@ -416,7 +525,8 @@ namespace GraphX.Controls
|
|||
}
|
||||
|
||||
#if WPF
|
||||
private static void OnDragFinished(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
|
||||
private static void OnVertexDragFinished(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
#elif METRO
|
||||
private static void OnDragFinished( object sender, PointerRoutedEventArgs e )
|
||||
#endif
|
||||
|
@ -445,7 +555,7 @@ namespace GraphX.Controls
|
|||
var element = sender as IInputElement;
|
||||
if (element != null)
|
||||
{
|
||||
element.MouseMove -= OnDragging;
|
||||
element.MouseMove -= OnVertexDragging;
|
||||
element.ReleaseMouseCapture();
|
||||
}
|
||||
#elif METRO
|
||||
|
@ -459,7 +569,8 @@ namespace GraphX.Controls
|
|||
}
|
||||
|
||||
#if WPF
|
||||
private static void OnDragging(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
|
||||
private static void OnVertexDragging(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
#elif METRO
|
||||
private static void OnDragging( object sender, PointerRoutedEventArgs e )
|
||||
#endif
|
||||
|
@ -578,6 +689,7 @@ namespace GraphX.Controls
|
|||
}
|
||||
|
||||
#if WPF
|
||||
|
||||
private static Point GetPositionInArea(GraphAreaBase area, System.Windows.Input.MouseEventArgs e)
|
||||
#elif METRO
|
||||
private static Windows.Foundation.Point GetPositionInArea(GraphAreaBase area, PointerRoutedEventArgs e)
|
||||
|
@ -609,4 +721,4 @@ namespace GraphX.Controls
|
|||
return area;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,16 @@ using GraphX.Controls.Models;
|
|||
using GraphX.PCL.Common.Enums;
|
||||
using GraphX.PCL.Common.Exceptions;
|
||||
using GraphX.PCL.Common.Interfaces;
|
||||
#if WPF
|
||||
using System.Windows.Input;
|
||||
|
||||
#if WPF
|
||||
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using SysRect = System.Windows.Rect;
|
||||
|
||||
#elif METRO
|
||||
using GraphX.PCL.Common;
|
||||
using GraphX.Measure;
|
||||
|
@ -33,10 +37,10 @@ namespace GraphX.Controls
|
|||
public abstract class EdgeControlBase : Control, IGraphControl, IDisposable
|
||||
{
|
||||
#if METRO
|
||||
void IPositionChangeNotify.OnPositionChanged()
|
||||
{
|
||||
//skip any actions on own position change
|
||||
}
|
||||
void IPositionChangeNotify.OnPositionChanged()
|
||||
{
|
||||
//skip any actions on own position change
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Properties & Fields
|
||||
|
@ -45,14 +49,18 @@ namespace GraphX.Controls
|
|||
/// Gets or sets if edge pointer should be hidden when source and target vertices are overlapped making the 0 length edge. Default value is True.
|
||||
/// </summary>
|
||||
public bool HideEdgePointerOnVertexOverlap { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the length of the edge to hide the edge pointers if less than or equal to. Default value is 0 (do not hide).
|
||||
/// </summary>
|
||||
public double HideEdgePointerByEdgeLength { get; set; } = 0.0d;
|
||||
|
||||
public abstract bool IsSelfLooped { get; protected set; }
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract void Clean();
|
||||
|
||||
protected DoubleCollection StrokeDashArray { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -70,8 +78,13 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
private SysRect _selfLoopedEdgeLastKnownRect;
|
||||
|
||||
protected virtual void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
|
||||
protected virtual void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
|
||||
protected virtual void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets parent GraphArea visual
|
||||
|
@ -85,15 +98,16 @@ namespace GraphX.Controls
|
|||
public static readonly DependencyProperty RootCanvasProperty =
|
||||
DependencyProperty.Register(nameof(RootArea), typeof(GraphAreaBase), typeof(EdgeControlBase), new PropertyMetadata(null));
|
||||
|
||||
|
||||
public static readonly DependencyProperty SelfLoopIndicatorRadiusProperty = DependencyProperty.Register(nameof(SelfLoopIndicatorRadius),
|
||||
typeof(double),
|
||||
typeof(EdgeControlBase),
|
||||
new PropertyMetadata(5d));
|
||||
|
||||
/// <summary>
|
||||
/// Radius of the default self-loop indicator, which is drawn as a circle (when custom template isn't provided). Default is 20.
|
||||
/// </summary>
|
||||
public double SelfLoopIndicatorRadius {
|
||||
public double SelfLoopIndicatorRadius
|
||||
{
|
||||
get { return (double)GetValue(SelfLoopIndicatorRadiusProperty); }
|
||||
set { SetValue(SelfLoopIndicatorRadiusProperty, value); }
|
||||
}
|
||||
|
@ -102,6 +116,7 @@ namespace GraphX.Controls
|
|||
typeof(Point),
|
||||
typeof(EdgeControlBase),
|
||||
new PropertyMetadata(new Point()));
|
||||
|
||||
/// <summary>
|
||||
/// Offset from the left-top corner of the vertex. Useful for custom vertex shapes. Default is 10,10.
|
||||
/// </summary>
|
||||
|
@ -115,6 +130,7 @@ namespace GraphX.Controls
|
|||
typeof(bool),
|
||||
typeof(EdgeControlBase),
|
||||
new PropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// Show self looped edge indicator on the vertex top-left corner. Default value is true.
|
||||
/// </summary>
|
||||
|
@ -124,7 +140,6 @@ namespace GraphX.Controls
|
|||
set { SetValue(ShowSelfLoopIndicatorProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source),
|
||||
typeof(VertexControl),
|
||||
typeof(EdgeControlBase),
|
||||
|
@ -145,14 +160,12 @@ namespace GraphX.Controls
|
|||
(d as EdgeControlBase)?.OnTargetChanged(d, e);
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty EdgeProperty = DependencyProperty.Register(nameof(Edge), typeof(object),
|
||||
typeof(EdgeControlBase),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
|
||||
|
||||
private double _labelAngle;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets vertex label angle
|
||||
/// </summary>
|
||||
|
@ -189,6 +202,7 @@ namespace GraphX.Controls
|
|||
case EdgeDashStyle.Dash:
|
||||
ec.StrokeDashArray = new DoubleCollection { 4.0, 2.0 };
|
||||
break;
|
||||
|
||||
case EdgeDashStyle.Dot:
|
||||
ec.StrokeDashArray = new DoubleCollection { 1.0, 2.0 };
|
||||
break;
|
||||
|
@ -208,7 +222,6 @@ namespace GraphX.Controls
|
|||
ec.UpdateEdge(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets edge dash style
|
||||
/// </summary>
|
||||
|
@ -217,7 +230,8 @@ namespace GraphX.Controls
|
|||
get { return (EdgeDashStyle)GetValue(DashStyleProperty); }
|
||||
set { SetValue(DashStyleProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion DashStyle
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if this edge can be paralellized if GraphArea.EnableParallelEdges is true.
|
||||
|
@ -231,6 +245,7 @@ namespace GraphX.Controls
|
|||
}
|
||||
|
||||
private bool _updateLabelPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if label position should be updated on edge update
|
||||
/// </summary>
|
||||
|
@ -240,6 +255,7 @@ namespace GraphX.Controls
|
|||
protected PropertyChangeNotifier _sourceWatcher;
|
||||
protected PropertyChangeNotifier _targetWatcher;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set if hidden edges should be updated when connected vertices positions are changed. Default value is True.
|
||||
/// </summary>
|
||||
|
@ -266,14 +282,15 @@ namespace GraphX.Controls
|
|||
public bool ShowArrows { get { return (bool)GetValue(ShowArrowsProperty); } set { SetValue(ShowArrowsProperty, value); } }
|
||||
|
||||
public static readonly DependencyProperty ShowLabelProperty = DependencyProperty.Register("ShowLabel",
|
||||
typeof (bool),
|
||||
typeof (EdgeControlBase),
|
||||
typeof(bool),
|
||||
typeof(EdgeControlBase),
|
||||
new PropertyMetadata(false, showlabel_changed));
|
||||
|
||||
private static void showlabel_changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as EdgeControlBase)?.UpdateEdge();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show edge label.Default value is False.
|
||||
/// </summary>
|
||||
|
@ -295,6 +312,7 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected bool _alignLabelsToEdges;
|
||||
|
||||
public static readonly DependencyProperty LabelVerticalOffsetProperty = DependencyProperty.Register("LabelVerticalOffset",
|
||||
|
@ -323,6 +341,7 @@ namespace GraphX.Controls
|
|||
protected Path LinePathObject;
|
||||
|
||||
private IEdgeLabelControl _edgeLabelControl;
|
||||
|
||||
/// <summary>
|
||||
/// Templated label control to display labels
|
||||
/// </summary>
|
||||
|
@ -335,6 +354,7 @@ namespace GraphX.Controls
|
|||
/// Returns edge pointer for source if any
|
||||
/// </summary>
|
||||
public IEdgePointer GetEdgePointerForSource() { return EdgePointerForSource; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns edge pointer for target if any
|
||||
/// </summary>
|
||||
|
@ -350,6 +370,7 @@ namespace GraphX.Controls
|
|||
get { return (VertexControl)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Target visual vertex object
|
||||
/// </summary>
|
||||
|
@ -359,7 +380,6 @@ namespace GraphX.Controls
|
|||
set { SetValue(TargetProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Data edge object
|
||||
/// </summary>
|
||||
|
@ -393,11 +413,11 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
public void UpdateLabel()
|
||||
{
|
||||
if(_edgeLabelControl != null && ShowLabel)
|
||||
if (_edgeLabelControl != null && ShowLabel)
|
||||
UpdateLabelLayout(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Properties & Fields
|
||||
|
||||
#region Position methods
|
||||
|
||||
|
@ -437,9 +457,11 @@ namespace GraphX.Controls
|
|||
{
|
||||
return new Measure.Point(final ? GraphAreaBase.GetFinalX(this) : GraphAreaBase.GetX(this), final ? GraphAreaBase.GetFinalY(this) : GraphAreaBase.GetY(this));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion Position methods
|
||||
|
||||
#region Manual path controls
|
||||
|
||||
/// <summary>
|
||||
/// Gets current edge path geometry object
|
||||
/// </summary>
|
||||
|
@ -458,7 +480,8 @@ namespace GraphX.Controls
|
|||
Linegeometry = geo;
|
||||
UpdateEdge();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion Manual path controls
|
||||
|
||||
internal void SetVisibility(Visibility value)
|
||||
{
|
||||
|
@ -470,8 +493,8 @@ namespace GraphX.Controls
|
|||
EdgeLabelControl?.UpdateLayout();
|
||||
if (LinePathObject != null)
|
||||
{
|
||||
var pos = Source.GetPosition();
|
||||
Source.SetPosition(pos.X, pos.Y);
|
||||
var pos = this.Source.GetPosition();
|
||||
this.Source.SetPosition(pos.X, pos.Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,12 +503,15 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
public bool IsTemplateLoaded => LinePathObject != null;
|
||||
|
||||
protected virtual void OnEdgeLabelUpdated() { }
|
||||
protected virtual void OnEdgeLabelUpdated()
|
||||
{
|
||||
}
|
||||
|
||||
#if WPF
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
#elif METRO
|
||||
protected override void OnApplyTemplate()
|
||||
protected override void OnApplyTemplate()
|
||||
#endif
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
@ -499,18 +525,17 @@ namespace GraphX.Controls
|
|||
throw new GX_ObsoleteException("PART_edgeArrowPath is obsolete! Please use new DefaultEdgePointer object in your EdgeControlBase template!");
|
||||
|
||||
EdgeLabelControl = EdgeLabelControl ?? GetTemplatePart("PART_edgeLabel") as IEdgeLabelControl;
|
||||
|
||||
|
||||
EdgePointerForSource = GetTemplatePart("PART_EdgePointerForSource") as IEdgePointer;
|
||||
EdgePointerForTarget = GetTemplatePart("PART_EdgePointerForTarget") as IEdgePointer;
|
||||
|
||||
SelfLoopIndicator = GetTemplatePart("PART_SelfLoopedEdge") as FrameworkElement;
|
||||
if(SelfLoopIndicator != null)
|
||||
if (SelfLoopIndicator != null)
|
||||
SelfLoopIndicator.LayoutUpdated += (sender, args) =>
|
||||
{
|
||||
SelfLoopIndicator?.Arrange(_selfLoopedEdgeLastKnownRect);
|
||||
};
|
||||
// var x = ShowLabel;
|
||||
// var x = ShowLabel;
|
||||
MeasureChild(EdgePointerForSource as UIElement);
|
||||
MeasureChild(EdgePointerForTarget as UIElement);
|
||||
MeasureChild(SelfLoopIndicator);
|
||||
|
@ -561,7 +586,6 @@ namespace GraphX.Controls
|
|||
LinePathObject.StrokeDashArray = StrokeDashArray;
|
||||
}
|
||||
|
||||
|
||||
internal int ParallelEdgeOffset;
|
||||
//internal int TargetOffset;
|
||||
|
||||
|
@ -583,10 +607,12 @@ namespace GraphX.Controls
|
|||
sourcepos.Y + source.DesiredSize.Height * .5 - sideDistance * (mainVector.X / mainVector.Length));
|
||||
return joint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal value to store last calculated Source vertex connection point
|
||||
/// </summary>
|
||||
protected internal Point? SourceConnectionPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Internal value to store last calculated Target vertex connection point
|
||||
/// </summary>
|
||||
|
@ -654,6 +680,206 @@ namespace GraphX.Controls
|
|||
else _selfLoopedEdgeLastKnownRect = new SysRect(pt, SelfLoopIndicator.DesiredSize);
|
||||
}
|
||||
|
||||
public virtual void PrepareEdgePathFromMousePointer(bool useCurrentCoords = false)
|
||||
{
|
||||
//do not calculate invisible edges
|
||||
if ((Visibility != Visibility.Visible && !IsHiddenEdgesUpdated) && ManualDrawing || !IsTemplateLoaded) return;
|
||||
|
||||
//get the size of the source
|
||||
var sourceSize = new Size
|
||||
{
|
||||
Width = this.Source.ActualWidth,
|
||||
Height = this.Source.ActualHeight
|
||||
};
|
||||
|
||||
//get the position center of the source
|
||||
var sourcePos = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Source) : GraphAreaBase.GetFinalX(this.Source)) + sourceSize.Width * 0.5,
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Source) : GraphAreaBase.GetFinalY(this.Source)) + sourceSize.Height * 0.5
|
||||
};
|
||||
|
||||
//get the size of the target
|
||||
var targetSize = new Size
|
||||
{
|
||||
Width = SystemParameters.CursorWidth,
|
||||
Height = SystemParameters.CursorHeight
|
||||
};
|
||||
|
||||
//get the position center of the target
|
||||
var targetPos = new Point
|
||||
{
|
||||
X = Mouse.GetPosition(this.RootArea).X,/* + targetSize.Width * 0.5,*/
|
||||
Y = Mouse.GetPosition(this.RootArea).Y/* + targetSize.Height * 0.5*/
|
||||
};
|
||||
|
||||
var routedEdge = this.Edge as IRoutingInfo;
|
||||
|
||||
if (routedEdge == null)
|
||||
throw new GX_InvalidDataException("Edge must implement IRoutingInfo interface");
|
||||
|
||||
//get the route informations
|
||||
var routeInformation = routedEdge.RoutingPoints;
|
||||
|
||||
// Get the TopLeft position of the Source Vertex.
|
||||
var sourcePos1 = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Source) : GraphAreaBase.GetFinalX(this.Source)),
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Source) : GraphAreaBase.GetFinalY(this.Source))
|
||||
};
|
||||
// Get the TopLeft position of the Target Vertex.
|
||||
var targetPos1 = new Point
|
||||
{
|
||||
X = Mouse.GetPosition(this.RootArea).X,
|
||||
Y = Mouse.GetPosition(this.RootArea).Y
|
||||
};
|
||||
|
||||
var hasEpSource = EdgePointerForSource != null;
|
||||
var hasEpTarget = EdgePointerForTarget != null;
|
||||
|
||||
//if self looped edge
|
||||
if (IsSelfLooped)
|
||||
{
|
||||
PrepareSelfLoopedEdge(sourcePos1);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if we have some edge route data
|
||||
var hasRouteInfo = routeInformation != null && routeInformation.Length > 1;
|
||||
|
||||
var gEdge = Edge as IGraphXCommonEdge;
|
||||
Point p1;
|
||||
Point p2;
|
||||
|
||||
//calculate edge source (p1) and target (p2) endpoints based on different settings
|
||||
if (gEdge?.SourceConnectionPointId != null)
|
||||
{
|
||||
var sourceCp = this.Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true);
|
||||
if (sourceCp == null)
|
||||
{
|
||||
throw new GX_ObjectNotFoundException(string.Format("Can't find source vertex VCP by edge source connection point Id({1}) : {0}", this.Source, gEdge.SourceConnectionPointId));
|
||||
}
|
||||
if (sourceCp.Shape == VertexShape.None) p1 = sourceCp.RectangularSize.Center();
|
||||
else
|
||||
{
|
||||
var targetCpPos = hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos);
|
||||
p1 = GeometryHelper.GetEdgeEndpoint(sourceCp.RectangularSize.Center(), sourceCp.RectangularSize, targetCpPos, sourceCp.Shape);
|
||||
}
|
||||
}
|
||||
else
|
||||
p1 = GeometryHelper.GetEdgeEndpoint(sourcePos, new SysRect(sourcePos1, sourceSize), (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos)), this.Source.VertexShape);
|
||||
|
||||
//if (gEdge?.TargetConnectionPointId != null)
|
||||
//{
|
||||
// //var targetCp = this.Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true);
|
||||
// //if (targetCp == null)
|
||||
// // throw new GX_ObjectNotFoundException(string.Format("Can't find target vertex VCP by edge target connection point Id({1}) : {0}", this.Target, gEdge.TargetConnectionPointId));
|
||||
// //if (targetCp.Shape == VertexShape.None) p2 = targetCp.RectangularSize.Center();
|
||||
// //else
|
||||
// //{
|
||||
// // var sourceCpPos = gEdge.SourceConnectionPointId.HasValue ? this.Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true).RectangularSize.Center() : hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos);
|
||||
// // p2 = GeometryHelper.GetEdgeEndpoint(targetCp.RectangularSize.Center(), targetCp.RectangularSize, sourceCpPos, targetCp.Shape);
|
||||
// //}
|
||||
//}
|
||||
//else
|
||||
p2 = GeometryHelper.GetEdgeEndpoint(
|
||||
targetPos, new SysRect(targetPos, targetSize), hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos), VertexShape.None);
|
||||
|
||||
SourceConnectionPoint = p1;
|
||||
TargetConnectionPoint = p2;
|
||||
|
||||
Linegeometry = new PathGeometry();
|
||||
PathFigure lineFigure = new PathFigure();
|
||||
|
||||
//if we have route and route consist of 2 or more points
|
||||
if (RootArea != null && hasRouteInfo)
|
||||
{
|
||||
//replace start and end points with accurate ones
|
||||
var routePoints = routeInformation.ToWindows().ToList();
|
||||
routePoints.Clear();
|
||||
routePoints.Add(p1);
|
||||
routePoints.Add(p2);
|
||||
|
||||
if (routedEdge.RoutingPoints != null)
|
||||
routedEdge.RoutingPoints = routePoints.ToArray().ToGraphX();
|
||||
|
||||
if (RootArea.EdgeCurvingEnabled)
|
||||
{
|
||||
var oPolyLineSegment = GeometryHelper.GetCurveThroughPoints(routePoints.ToArray(), 0.5, RootArea.EdgeCurvingTolerance);
|
||||
|
||||
if (hasEpTarget)
|
||||
{
|
||||
UpdateTargetEpData(oPolyLineSegment.Points[oPolyLineSegment.Points.Count - 1], oPolyLineSegment.Points[oPolyLineSegment.Points.Count - 2]);
|
||||
oPolyLineSegment.Points.RemoveAt(oPolyLineSegment.Points.Count - 1);
|
||||
}
|
||||
if (hasEpSource)
|
||||
{
|
||||
UpdateSourceEpData(oPolyLineSegment.Points.First(), oPolyLineSegment.Points[1]);
|
||||
oPolyLineSegment.Points.RemoveAt(0);
|
||||
}
|
||||
|
||||
lineFigure = GeometryHelper.GetPathFigureFromPathSegments(routePoints[0], true, true, oPolyLineSegment);
|
||||
#if WPF
|
||||
//freeze and create resulting geometry
|
||||
GeometryHelper.TryFreeze(oPolyLineSegment);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasEpSource)
|
||||
routePoints[0] = routePoints[0].Subtract(UpdateSourceEpData(routePoints.First(), routePoints[1]));
|
||||
if (hasEpTarget)
|
||||
routePoints[routePoints.Count - 1] = routePoints[routePoints.Count - 1].Subtract(UpdateTargetEpData(p2, routePoints[routePoints.Count - 2]));
|
||||
|
||||
// Reverse the path if specified.
|
||||
if (gEdge.ReversePath)
|
||||
routePoints.Reverse();
|
||||
|
||||
var pcol = new PointCollection();
|
||||
routePoints.ForEach(a => pcol.Add(a));
|
||||
|
||||
lineFigure = new PathFigure { StartPoint = p1, Segments = new PathSegmentCollection { new PolyLineSegment { Points = pcol } }, IsClosed = false };
|
||||
}
|
||||
}
|
||||
else // no route defined
|
||||
{
|
||||
bool remainHidden = false;
|
||||
//check for hide only if prop is not 0
|
||||
if (HideEdgePointerByEdgeLength != 0d)
|
||||
{
|
||||
if (MathHelper.GetDistanceBetweenPoints(p1, p2) <= HideEdgePointerByEdgeLength)
|
||||
{
|
||||
EdgePointerForSource?.Hide();
|
||||
EdgePointerForTarget?.Hide();
|
||||
remainHidden = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
EdgePointerForSource?.Show();
|
||||
EdgePointerForTarget?.Show();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasEpSource)
|
||||
p1 = p1.Subtract(UpdateSourceEpData(p1, p2, remainHidden));
|
||||
if (hasEpTarget)
|
||||
p2 = p2.Subtract(UpdateTargetEpData(p2, p1, remainHidden));
|
||||
|
||||
lineFigure = new PathFigure { StartPoint = gEdge.ReversePath ? p2 : p1, Segments = new PathSegmentCollection { new LineSegment() { Point = gEdge.ReversePath ? p1 : p2 } }, IsClosed = false };
|
||||
}
|
||||
((PathGeometry)Linegeometry).Figures.Add(lineFigure);
|
||||
#if WPF
|
||||
GeometryHelper.TryFreeze(lineFigure);
|
||||
GeometryHelper.TryFreeze(Linegeometry);
|
||||
#endif
|
||||
if (ShowLabel && EdgeLabelControl != null && _updateLabelPosition)
|
||||
EdgeLabelControl.UpdatePosition();
|
||||
|
||||
if (LinePathObject == null) return;
|
||||
LinePathObject.Data = Linegeometry;
|
||||
LinePathObject.StrokeDashArray = StrokeDashArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create and apply edge path using calculated ER parameters stored in edge
|
||||
/// </summary>
|
||||
|
@ -663,29 +889,30 @@ namespace GraphX.Controls
|
|||
public virtual void PrepareEdgePath(bool useCurrentCoords = false, Measure.Point[] externalRoutingPoints = null, bool updateLabel = true)
|
||||
{
|
||||
//do not calculate invisible edges
|
||||
if ((Visibility != Visibility.Visible && !IsHiddenEdgesUpdated) && Source == null || Target == null || ManualDrawing || !IsTemplateLoaded) return;
|
||||
if ((Visibility != Visibility.Visible && !IsHiddenEdgesUpdated) && this.Source == null || this.Target == null || ManualDrawing || !IsTemplateLoaded) return;
|
||||
|
||||
#region Get the inputs
|
||||
|
||||
//get the size of the source
|
||||
var sourceSize = new Size
|
||||
{
|
||||
Width = Source.ActualWidth,
|
||||
Height = Source.ActualHeight
|
||||
Width = this.Source.ActualWidth,
|
||||
Height = this.Source.ActualHeight
|
||||
};
|
||||
if (CustomHelper.IsInDesignMode(this)) sourceSize = new Size(80, 20);
|
||||
|
||||
//get the position center of the source
|
||||
var sourcePos = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(Source) : GraphAreaBase.GetFinalX(Source)) + sourceSize.Width * .5,
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(Source) : GraphAreaBase.GetFinalY(Source)) + sourceSize.Height * .5
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Source) : GraphAreaBase.GetFinalX(this.Source)) + sourceSize.Width * .5,
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Source) : GraphAreaBase.GetFinalY(this.Source)) + sourceSize.Height * .5
|
||||
};
|
||||
|
||||
//get the size of the target
|
||||
var targetSize = new Size
|
||||
{
|
||||
Width = Target.ActualWidth,
|
||||
Height = Target.ActualHeight
|
||||
Width = this.Target.ActualWidth,
|
||||
Height = this.Target.ActualHeight
|
||||
};
|
||||
if (CustomHelper.IsInDesignMode(this))
|
||||
targetSize = new Size(80, 20);
|
||||
|
@ -693,8 +920,8 @@ namespace GraphX.Controls
|
|||
//get the position center of the target
|
||||
var targetPos = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(Target) : GraphAreaBase.GetFinalX(Target)) + targetSize.Width * .5,
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(Target) : GraphAreaBase.GetFinalY(Target)) + targetSize.Height * .5
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Target) : GraphAreaBase.GetFinalX(this.Target)) + targetSize.Width * .5,
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Target) : GraphAreaBase.GetFinalY(this.Target)) + targetSize.Height * .5
|
||||
};
|
||||
|
||||
var routedEdge = Edge as IRoutingInfo;
|
||||
|
@ -707,19 +934,20 @@ namespace GraphX.Controls
|
|||
// Get the TopLeft position of the Source Vertex.
|
||||
var sourcePos1 = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(Source) : GraphAreaBase.GetFinalX(Source)),
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(Source) : GraphAreaBase.GetFinalY(Source))
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Source) : GraphAreaBase.GetFinalX(this.Source)),
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Source) : GraphAreaBase.GetFinalY(this.Source))
|
||||
};
|
||||
// Get the TopLeft position of the Target Vertex.
|
||||
var targetPos1 = new Point
|
||||
{
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(Target) : GraphAreaBase.GetFinalX(Target)),
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(Target) : GraphAreaBase.GetFinalY(Target))
|
||||
X = (useCurrentCoords ? GraphAreaBase.GetX(this.Target) : GraphAreaBase.GetFinalX(this.Target)),
|
||||
Y = (useCurrentCoords ? GraphAreaBase.GetY(this.Target) : GraphAreaBase.GetFinalY(this.Target))
|
||||
};
|
||||
|
||||
var hasEpSource = EdgePointerForSource != null;
|
||||
var hasEpTarget = EdgePointerForTarget != null;
|
||||
#endregion
|
||||
|
||||
#endregion Get the inputs
|
||||
|
||||
//if self looped edge
|
||||
if (IsSelfLooped)
|
||||
|
@ -734,8 +962,8 @@ namespace GraphX.Controls
|
|||
//calculate source and target edge attach points
|
||||
if (RootArea != null && !hasRouteInfo && RootArea.EnableParallelEdges && ParallelEdgeOffset != 0)
|
||||
{
|
||||
sourcePos = GetParallelOffset(Source, Target, ParallelEdgeOffset);
|
||||
targetPos = GetParallelOffset(Target, Source, -ParallelEdgeOffset);
|
||||
sourcePos = GetParallelOffset(this.Source, this.Target, ParallelEdgeOffset);
|
||||
targetPos = GetParallelOffset(this.Target, this.Source, -ParallelEdgeOffset);
|
||||
}
|
||||
|
||||
/* Rectangular shapes implementation by bleibold */
|
||||
|
@ -747,38 +975,38 @@ namespace GraphX.Controls
|
|||
//calculate edge source (p1) and target (p2) endpoints based on different settings
|
||||
if (gEdge?.SourceConnectionPointId != null)
|
||||
{
|
||||
var sourceCp = Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true);
|
||||
var sourceCp = this.Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true);
|
||||
if (sourceCp == null)
|
||||
throw new GX_ObjectNotFoundException(string.Format("Can't find source vertex VCP by edge source connection point Id({1}) : {0}", Source, gEdge.SourceConnectionPointId));
|
||||
throw new GX_ObjectNotFoundException(string.Format("Can't find source vertex VCP by edge source connection point Id({1}) : {0}", this.Source, gEdge.SourceConnectionPointId));
|
||||
if (sourceCp.Shape == VertexShape.None) p1 = sourceCp.RectangularSize.Center();
|
||||
else
|
||||
{
|
||||
var targetCpPos = gEdge.TargetConnectionPointId.HasValue ? Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true).RectangularSize.Center() : (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos));
|
||||
var targetCpPos = gEdge.TargetConnectionPointId.HasValue ? this.Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true).RectangularSize.Center() : (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos));
|
||||
p1 = GeometryHelper.GetEdgeEndpoint(sourceCp.RectangularSize.Center(), sourceCp.RectangularSize, targetCpPos, sourceCp.Shape);
|
||||
}
|
||||
}
|
||||
else
|
||||
p1 = GeometryHelper.GetEdgeEndpoint(sourcePos, new SysRect(sourcePos1, sourceSize), (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos)), Source.VertexShape);
|
||||
p1 = GeometryHelper.GetEdgeEndpoint(sourcePos, new SysRect(sourcePos1, sourceSize), (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos)), this.Source.VertexShape);
|
||||
|
||||
if (gEdge?.TargetConnectionPointId != null)
|
||||
{
|
||||
var targetCp = Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true);
|
||||
var targetCp = this.Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true);
|
||||
if (targetCp == null)
|
||||
throw new GX_ObjectNotFoundException(string.Format("Can't find target vertex VCP by edge target connection point Id({1}) : {0}", Target, gEdge.TargetConnectionPointId));
|
||||
throw new GX_ObjectNotFoundException(string.Format("Can't find target vertex VCP by edge target connection point Id({1}) : {0}", this.Target, gEdge.TargetConnectionPointId));
|
||||
if (targetCp.Shape == VertexShape.None) p2 = targetCp.RectangularSize.Center();
|
||||
else
|
||||
{
|
||||
var sourceCpPos = gEdge.SourceConnectionPointId.HasValue ? Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true).RectangularSize.Center() : hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos);
|
||||
var sourceCpPos = gEdge.SourceConnectionPointId.HasValue ? this.Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true).RectangularSize.Center() : hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos);
|
||||
p2 = GeometryHelper.GetEdgeEndpoint(targetCp.RectangularSize.Center(), targetCp.RectangularSize, sourceCpPos, targetCp.Shape);
|
||||
}
|
||||
}
|
||||
else
|
||||
p2 = GeometryHelper.GetEdgeEndpoint(targetPos, new SysRect(targetPos1, targetSize), hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos), Target.VertexShape);
|
||||
p2 = GeometryHelper.GetEdgeEndpoint(targetPos, new SysRect(targetPos1, targetSize), hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos), this.Target.VertexShape);
|
||||
|
||||
SourceConnectionPoint = p1;
|
||||
TargetConnectionPoint = p2;
|
||||
|
||||
Linegeometry = new PathGeometry();
|
||||
Linegeometry = new PathGeometry();
|
||||
PathFigure lineFigure;
|
||||
|
||||
//if we have route and route consist of 2 or more points
|
||||
|
@ -817,21 +1045,20 @@ namespace GraphX.Controls
|
|||
}
|
||||
else
|
||||
{
|
||||
if (hasEpSource)
|
||||
if (hasEpSource)
|
||||
routePoints[0] = routePoints[0].Subtract(UpdateSourceEpData(routePoints.First(), routePoints[1]));
|
||||
if (hasEpTarget)
|
||||
routePoints[routePoints.Count - 1] = routePoints[routePoints.Count - 1].Subtract(UpdateTargetEpData(p2, routePoints[routePoints.Count - 2]));
|
||||
|
||||
// Reverse the path if specified.
|
||||
if (gEdge.ReversePath)
|
||||
routePoints.Reverse();
|
||||
if (gEdge.ReversePath)
|
||||
routePoints.Reverse();
|
||||
|
||||
var pcol = new PointCollection();
|
||||
routePoints.ForEach(a=> pcol.Add(a));
|
||||
|
||||
routePoints.ForEach(a => pcol.Add(a));
|
||||
|
||||
lineFigure = new PathFigure { StartPoint = p1, Segments = new PathSegmentCollection { new PolyLineSegment { Points = pcol } }, IsClosed = false };
|
||||
}
|
||||
|
||||
}
|
||||
else // no route defined
|
||||
{
|
||||
|
@ -852,12 +1079,12 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
|
||||
if (hasEpSource)
|
||||
if (hasEpSource)
|
||||
p1 = p1.Subtract(UpdateSourceEpData(p1, p2, allowUpdateEpDataToUnsuppress));
|
||||
if (hasEpTarget)
|
||||
p2 = p2.Subtract(UpdateTargetEpData(p2, p1, allowUpdateEpDataToUnsuppress));
|
||||
|
||||
lineFigure = new PathFigure { StartPoint = gEdge.ReversePath ? p2 : p1, Segments = new PathSegmentCollection { new LineSegment() { Point = gEdge.ReversePath ? p1 : p2 } }, IsClosed = false };
|
||||
lineFigure = new PathFigure { StartPoint = gEdge.ReversePath ? p2 : p1, Segments = new PathSegmentCollection { new LineSegment() { Point = gEdge.ReversePath ? p1 : p2 } }, IsClosed = false };
|
||||
}
|
||||
((PathGeometry)Linegeometry).Figures.Add(lineFigure);
|
||||
#if WPF
|
||||
|
@ -876,7 +1103,7 @@ namespace GraphX.Controls
|
|||
if (HideEdgePointerOnVertexOverlap) EdgePointerForSource.Suppress();
|
||||
else dir = new Vector(0, 0);
|
||||
}
|
||||
else if(allowUnsuppress) EdgePointerForSource.UnSuppress();
|
||||
else if (allowUnsuppress) EdgePointerForSource.UnSuppress();
|
||||
var result = EdgePointerForSource.Update(from, dir, EdgePointerForSource.NeedRotation ? -MathHelper.GetAngleBetweenPoints(from, to).ToDegrees() : 0);
|
||||
return EdgePointerForSource.Visibility == Visibility.Visible ? result : new Point();
|
||||
}
|
||||
|
@ -890,11 +1117,11 @@ namespace GraphX.Controls
|
|||
else dir = new Vector(0, 0);
|
||||
}
|
||||
else if (allowUnsuppress) EdgePointerForTarget.UnSuppress();
|
||||
var result = EdgePointerForTarget.Update(from, dir, EdgePointerForTarget.NeedRotation ? (-MathHelper.GetAngleBetweenPoints(from, to).ToDegrees()) : 0);
|
||||
var result = EdgePointerForTarget.Update(from, dir, EdgePointerForTarget.NeedRotation ? (-MathHelper.GetAngleBetweenPoints(from, to).ToDegrees()) : 0);
|
||||
return EdgePointerForTarget.Visibility == Visibility.Visible ? result : new Point();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion public PrepareEdgePath()
|
||||
|
||||
/// <summary>
|
||||
/// Searches and returns template part by name if found
|
||||
|
@ -906,7 +1133,7 @@ namespace GraphX.Controls
|
|||
#if WPF
|
||||
return Template.FindName(name, this);
|
||||
#elif METRO
|
||||
return this.FindDescendantByName(name);
|
||||
return this.FindDescendantByName(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -931,4 +1158,4 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,8 +66,8 @@ namespace GraphX.Controls
|
|||
DependencyProperty.Register(nameof(LogicCore), typeof(IGXLogicCore<TVertex, TEdge, TGraph>), typeof(GraphArea<TVertex, TEdge, TGraph>), new PropertyMetadata(null, logic_core_changed));
|
||||
|
||||
private static
|
||||
#if METRO
|
||||
async
|
||||
#if METRO
|
||||
async
|
||||
#endif
|
||||
void logic_core_changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
@ -164,7 +164,7 @@ namespace GraphX.Controls
|
|||
internal override double EdgeCurvingTolerance => LogicCore?.EdgeCurvingTolerance ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Add custom control for
|
||||
/// Add custom control for
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public virtual void AddCustomChildControl(UIElement control)
|
||||
|
@ -302,9 +302,10 @@ namespace GraphX.Controls
|
|||
/// Returns first vertex that is found under specified coordinates
|
||||
/// </summary>
|
||||
/// <param name="position">GraphArea coordinate space position</param>
|
||||
public virtual VertexControl GetVertexControlAt(Point position)
|
||||
public override VertexControl GetVertexControlAt(Point position)
|
||||
{
|
||||
Measure(new USize(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
return VertexList.Values.FirstOrDefault(a =>
|
||||
{
|
||||
var pos = a.GetPosition();
|
||||
|
@ -698,7 +699,7 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
public Dictionary<TVertex, Size> GetVertexSizes()
|
||||
{
|
||||
//measure if needed and get all vertex sizes
|
||||
//measure if needed and get all vertex sizes
|
||||
Measure(new USize(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var vertexSizes = new Dictionary<TVertex, Size>(_vertexlist.Count(a => ((IGraphXVertex)a.Value.Vertex).SkipProcessing != ProcessingOptionEnum.Exclude));
|
||||
//go through the vertex presenters and get the actual layoutpositions
|
||||
|
@ -814,7 +815,7 @@ namespace GraphX.Controls
|
|||
private CancellationTokenSource _layoutCancellationSource;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if visual graph should be updated if graph is filtered.
|
||||
/// Gets or sets if visual graph should be updated if graph is filtered.
|
||||
/// Remove all visuals with no keys in data graph and add all visuals that has keys in data graph.
|
||||
/// Default value is True.
|
||||
/// </summary>
|
||||
|
@ -896,7 +897,7 @@ namespace GraphX.Controls
|
|||
if (!localLogicCore.GenerateAlgorithmStorage(vertexSizes, vertexPositions))
|
||||
return;
|
||||
|
||||
//clear routing info
|
||||
//clear routing info
|
||||
localLogicCore.Graph.Edges.ForEach(a => a.RoutingPoints = null);
|
||||
|
||||
var resultCoords = localLogicCore.Compute(cancellationToken);
|
||||
|
@ -971,7 +972,7 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
/// <param name="generateAllEdges">Generate all available edges for graph</param>
|
||||
#if WPF
|
||||
public virtual void RelayoutGraph(bool generateAllEdges = false)
|
||||
public override void RelayoutGraph(bool generateAllEdges = false)
|
||||
{
|
||||
LogicCore.PushFilters();
|
||||
_relayoutGraphMain(generateAllEdges);
|
||||
|
@ -1192,7 +1193,7 @@ namespace GraphX.Controls
|
|||
if (LogicCore.Graph == null)
|
||||
throw new InvalidDataException("GraphArea.GenerateGraph() -> LogicCore.Graph property is null while trying to generate graph!");
|
||||
|
||||
LogicCore.PushFilters();
|
||||
LogicCore.PushFilters();
|
||||
if (AutoAssignMissingDataId)
|
||||
AutoresolveIds(false, graph);
|
||||
if (!LogicCore.IsCustomLayout)
|
||||
|
@ -1326,6 +1327,7 @@ namespace GraphX.Controls
|
|||
|
||||
protected void ReapplySingleEdgeVisualProperties(EdgeControl item)
|
||||
{
|
||||
if (this._edgesDragEnabled != null) DragBehaviour.SetIsDragEnabled(item, this._edgesDragEnabled.Value);
|
||||
if (_svEdgeDashStyle != null) item.DashStyle = _svEdgeDashStyle.Value;
|
||||
if (_svShowEdgeArrows != null) item.SetCurrentValue(EdgeControlBase.ShowArrowsProperty, _svShowEdgeArrows.Value);
|
||||
if (_svShowEdgeLabels != null) item.ShowLabel = _svShowEdgeLabels.Value;
|
||||
|
@ -1435,6 +1437,21 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
|
||||
private bool? _edgesDragEnabled;
|
||||
/// <summary>
|
||||
/// Sets drag mode for all edges
|
||||
/// </summary>
|
||||
/// <param name="isEnabled">Is drag mode enabled</param>
|
||||
public void SetEdgesDrag(bool isEnabled)
|
||||
{
|
||||
_edgesDragEnabled = isEnabled;
|
||||
|
||||
foreach (var item in EdgesList)
|
||||
{
|
||||
DragBehaviour.SetIsDragEnabled(item.Value, isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private VertexShape? _svVertexShape;// = VertexShape.Rectangle;
|
||||
/// <summary>
|
||||
/// Sets math shape for all vertices
|
||||
|
@ -1515,7 +1532,7 @@ namespace GraphX.Controls
|
|||
{
|
||||
if (LogicCore == null)
|
||||
throw new GX_InvalidDataException("LogicCore -> Not initialized!");
|
||||
RemoveAllEdges();
|
||||
RemoveAllEdges();
|
||||
|
||||
AutoresolveEdgeIds();
|
||||
|
||||
|
@ -1785,7 +1802,7 @@ namespace GraphX.Controls
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get controls related to specified control
|
||||
/// Get controls related to specified control
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Original control</param>
|
||||
/// <param name="resultType">Type of resulting related controls</param>
|
||||
|
@ -1966,7 +1983,7 @@ namespace GraphX.Controls
|
|||
/// <summary>
|
||||
/// Export current graph layout into the JPEG image file. layout will be saved in full size.
|
||||
/// </summary>
|
||||
/// <param name="quality">Optional image quality parameter</param>
|
||||
/// <param name="quality">Optional image quality parameter</param>
|
||||
public virtual void ExportAsJpeg(int quality = 100)
|
||||
{
|
||||
ExportAsImageDialog(ImageType.JPEG, true, PrintHelper.DEFAULT_DPI, quality);
|
||||
|
@ -1978,7 +1995,7 @@ namespace GraphX.Controls
|
|||
/// <param name="itype">Image format</param>
|
||||
/// <param name="dpi">Optional image DPI parameter</param>
|
||||
/// <param name="useZoomControlSurface">Use zoom control parent surface to render bitmap (only visible zoom content will be exported)</param>
|
||||
/// <param name="quality">Optional image quality parameter (for JPEG)</param>
|
||||
/// <param name="quality">Optional image quality parameter (for JPEG)</param>
|
||||
public virtual void ExportAsImageDialog(ImageType itype, bool useZoomControlSurface = false, double dpi = PrintHelper.DEFAULT_DPI, int quality = 100)
|
||||
{
|
||||
#if WPF
|
||||
|
@ -2030,7 +2047,7 @@ namespace GraphX.Controls
|
|||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Sets GraphArea into printing mode when its size will be recalculated on each measuer and child controls will be arranged accordingly.
|
||||
/// Sets GraphArea into printing mode when its size will be recalculated on each measuer and child controls will be arranged accordingly.
|
||||
/// Use with caution. Can spoil normal work while active but is essential to set before printing or grabbing an image.
|
||||
/// </summary>
|
||||
/// <param name="value">True or False</param>
|
||||
|
@ -2168,7 +2185,7 @@ namespace GraphX.Controls
|
|||
|
||||
protected virtual void CreateNewStateStorage()
|
||||
{
|
||||
_stateStorage = new StateStorage<TVertex, TEdge, TGraph>(this);
|
||||
_stateStorage = new StateStorage<TVertex, TEdge, TGraph>(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -510,6 +510,10 @@ namespace GraphX
|
|||
/// <returns></returns>
|
||||
public abstract VertexControl[] GetAllVertexControls();
|
||||
|
||||
public abstract VertexControl GetVertexControlAt(Point position);
|
||||
|
||||
public abstract void RelayoutGraph(bool generateAllEdges = false);
|
||||
|
||||
// INTERNAL VARIABLES FOR CONTROLS INTEROPERABILITY
|
||||
internal abstract bool IsEdgeRoutingEnabled { get; }
|
||||
internal abstract bool EnableParallelEdges { get; }
|
||||
|
@ -518,20 +522,20 @@ namespace GraphX
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// Get controls related to specified control
|
||||
/// Get controls related to specified control
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Original control</param>
|
||||
/// <param name="resultType">Type of resulting related controls</param>
|
||||
/// <param name="edgesType">Optional edge controls type</param>
|
||||
public abstract List<IGraphControl> GetRelatedControls(IGraphControl ctrl, GraphControlType resultType = GraphControlType.VertexAndEdge, EdgesType edgesType = EdgesType.Out);
|
||||
/// <summary>
|
||||
/// Get vertex controls related to specified control
|
||||
/// Get vertex controls related to specified control
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Original control</param>
|
||||
/// <param name="edgesType">Edge types to query for vertices</param>
|
||||
public abstract List<IGraphControl> GetRelatedVertexControls(IGraphControl ctrl, EdgesType edgesType = EdgesType.All);
|
||||
/// <summary>
|
||||
/// Get edge controls related to specified control
|
||||
/// Get edge controls related to specified control
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Original control</param>
|
||||
/// <param name="edgesType">Edge types to query</param>
|
||||
|
@ -641,11 +645,11 @@ namespace GraphX
|
|||
return DesignerProperties.GetIsInDesignMode(this) ? DesignSize : (IsInPrintMode ? ContentSize.Size : new Size(10, 10));
|
||||
#elif METRO
|
||||
return DesignMode.DesignModeEnabled ? DesignSize : new Size(10, 10);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden measure. It calculates a size where all of
|
||||
/// Overridden measure. It calculates a size where all of
|
||||
/// of the vertices are visible.
|
||||
/// </summary>
|
||||
/// <param name="constraint">The size constraint.</param>
|
||||
|
@ -660,7 +664,7 @@ namespace GraphX
|
|||
foreach (UIElement child in InternalChildren)
|
||||
#elif METRO
|
||||
foreach (UIElement child in Children)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
//measure the child
|
||||
child.Measure(constraint);
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#if WPF
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
#elif METRO
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#endif
|
||||
|
||||
using GraphX.PCL.Common.Enums;
|
||||
|
||||
namespace GraphX.Controls
|
||||
|
@ -22,11 +25,10 @@ namespace GraphX.Controls
|
|||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
|
||||
public static readonly DependencyProperty ShapeProperty =
|
||||
DependencyProperty.Register(nameof(Shape),
|
||||
typeof(VertexShape),
|
||||
typeof(StaticVertexConnectionPoint),
|
||||
DependencyProperty.Register(nameof(Shape),
|
||||
typeof(VertexShape),
|
||||
typeof(StaticVertexConnectionPoint),
|
||||
new PropertyMetadata(VertexShape.Circle));
|
||||
|
||||
/// <summary>
|
||||
|
@ -38,12 +40,13 @@ namespace GraphX.Controls
|
|||
set { SetValue(ShapeProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
private Rect _rectangularSize;
|
||||
public Rect RectangularSize {
|
||||
get
|
||||
{
|
||||
if(_rectangularSize == Rect.Empty)
|
||||
|
||||
public Rect RectangularSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_rectangularSize == Rect.Empty)
|
||||
UpdateLayout();
|
||||
return _rectangularSize;
|
||||
}
|
||||
|
@ -79,7 +82,7 @@ namespace GraphX.Controls
|
|||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Common part
|
||||
|
||||
private VertexControl _vertexControl;
|
||||
protected VertexControl VertexControl => _vertexControl ?? (_vertexControl = GetVertexControl(GetParent()));
|
||||
|
@ -101,7 +104,9 @@ namespace GraphX.Controls
|
|||
{
|
||||
_vertexControl = null;
|
||||
}
|
||||
|
||||
#if WPF
|
||||
|
||||
public DependencyObject GetParent()
|
||||
{
|
||||
return VisualParent;
|
||||
|
@ -114,6 +119,7 @@ namespace GraphX.Controls
|
|||
position = new Point(position.X + vPos.X, position.Y + vPos.Y);
|
||||
RectangularSize = new Rect(position, DesiredSize);
|
||||
}
|
||||
|
||||
#elif METRO
|
||||
public DependencyObject GetParent()
|
||||
{
|
||||
|
@ -129,4 +135,4 @@ namespace GraphX.Controls
|
|||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
#if WPF
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Controls;
|
||||
|
||||
#elif METRO
|
||||
using MouseEventArgs = Windows.UI.Xaml.Input.PointerRoutedEventArgs;
|
||||
using MouseButtonEventArgs = Windows.UI.Xaml.Input.PointerRoutedEventArgs;
|
||||
|
@ -12,18 +15,19 @@ using Windows.UI.Xaml;
|
|||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#endif
|
||||
|
||||
using GraphX.PCL.Common.Enums;
|
||||
using GraphX.PCL.Common.Exceptions;
|
||||
using GraphX.Controls.Models;
|
||||
using GraphX.PCL.Common.Interfaces;
|
||||
|
||||
|
||||
namespace GraphX.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual vertex control
|
||||
/// </summary>
|
||||
#if WPF
|
||||
|
||||
[Serializable]
|
||||
#endif
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = "Normal")]
|
||||
|
@ -33,9 +37,10 @@ namespace GraphX.Controls
|
|||
[TemplateVisualState(GroupName = "CommonStates", Name = "Disabled")]
|
||||
[TemplatePart(Name = "PART_vertexLabel", Type = typeof(IVertexLabelControl))]
|
||||
[TemplatePart(Name = "PART_vcproot", Type = typeof(Panel))]
|
||||
public class VertexControl: VertexControlBase
|
||||
public class VertexControl : VertexControlBase
|
||||
{
|
||||
#if WPF
|
||||
|
||||
static VertexControl()
|
||||
{
|
||||
//override the StyleKey Property
|
||||
|
@ -54,16 +59,15 @@ namespace GraphX.Controls
|
|||
Vertex = vertexData;
|
||||
|
||||
EventOptions = new VertexEventOptions(this) { PositionChangeNotification = tracePositionChange };
|
||||
foreach(var item in Enum.GetValues(typeof(EventType)).Cast<EventType>())
|
||||
foreach (var item in Enum.GetValues(typeof(EventType)).Cast<EventType>())
|
||||
UpdateEventhandling(item);
|
||||
}
|
||||
|
||||
|
||||
#region Position trace feature
|
||||
|
||||
|
||||
private ChangeMonitor _xChangeMonitor;
|
||||
private ChangeMonitor _yChangeMonitor;
|
||||
|
||||
internal void UpdatePositionTraceState()
|
||||
{
|
||||
if (EventOptions.PositionChangeNotification)
|
||||
|
@ -100,12 +104,12 @@ namespace GraphX.Controls
|
|||
|
||||
private void changeMonitor_ChangeDetected(object source, EventArgs args)
|
||||
{
|
||||
if(ShowLabel)
|
||||
if (ShowLabel)
|
||||
VertexLabelControl?.UpdatePosition();
|
||||
OnPositionChanged(new Point(), GetPosition());
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Position trace feature
|
||||
|
||||
public T FindDescendant<T>(string name)
|
||||
{
|
||||
|
@ -115,7 +119,7 @@ namespace GraphX.Controls
|
|||
#region Event tracing
|
||||
|
||||
private bool _clickTrack;
|
||||
private Point _clickTrackPoint;
|
||||
private Point _clickTrackPoint;
|
||||
|
||||
internal void UpdateEventhandling(EventType typ)
|
||||
{
|
||||
|
@ -133,22 +137,27 @@ namespace GraphX.Controls
|
|||
PreviewMouseMove -= VertexControl_PreviewMouseMove;
|
||||
}
|
||||
break;
|
||||
|
||||
case EventType.MouseDoubleClick:
|
||||
if (EventOptions.MouseDoubleClickEnabled) MouseDoubleClick += VertexControl_MouseDoubleClick;
|
||||
else MouseDoubleClick -= VertexControl_MouseDoubleClick;
|
||||
break;
|
||||
|
||||
case EventType.MouseMove:
|
||||
if (EventOptions.MouseMoveEnabled) MouseMove += VertexControl_MouseMove;
|
||||
else MouseMove -= VertexControl_MouseMove;
|
||||
break;
|
||||
|
||||
case EventType.MouseEnter:
|
||||
if (EventOptions.MouseEnterEnabled) MouseEnter += VertexControl_MouseEnter;
|
||||
else MouseEnter -= VertexControl_MouseEnter;
|
||||
break;
|
||||
|
||||
case EventType.MouseLeave:
|
||||
if (EventOptions.MouseLeaveEnabled) MouseLeave += VertexControl_MouseLeave;
|
||||
else MouseLeave -= VertexControl_MouseLeave;
|
||||
break;
|
||||
|
||||
case EventType.PositionChangeNotify:
|
||||
UpdatePositionTraceState();
|
||||
break;
|
||||
|
@ -157,18 +166,18 @@ namespace GraphX.Controls
|
|||
MouseUp += VertexControl_MouseUp;
|
||||
}
|
||||
|
||||
void VertexControl_PreviewMouseMove(object sender, MouseEventArgs e)
|
||||
private void VertexControl_PreviewMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!_clickTrack)
|
||||
return;
|
||||
if (!_clickTrack)
|
||||
return;
|
||||
|
||||
var curPoint = RootArea != null ? Mouse.GetPosition(RootArea) : new Point();
|
||||
|
||||
if (curPoint != _clickTrackPoint)
|
||||
_clickTrack = false;
|
||||
if (curPoint != _clickTrackPoint)
|
||||
_clickTrack = false;
|
||||
}
|
||||
|
||||
void VertexControl_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
private void VertexControl_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
{
|
||||
|
@ -183,33 +192,35 @@ namespace GraphX.Controls
|
|||
e.Handled = true;
|
||||
}
|
||||
|
||||
void VertexControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
private void VertexControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexDoubleClick(this, e);
|
||||
//e.Handled = true;
|
||||
}
|
||||
|
||||
void VertexControl_Down(object sender, MouseButtonEventArgs e)
|
||||
private void VertexControl_Down(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexSelected(this, e, Keyboard.Modifiers);
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexSelected(this, e, Keyboard.Modifiers);
|
||||
_clickTrack = true;
|
||||
_clickTrackPoint = RootArea != null ? Mouse.GetPosition(RootArea) : new Point();
|
||||
_clickTrackPoint = RootArea != null ? Mouse.GetPosition(RootArea) : new Point();
|
||||
e.Handled = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion Event tracing
|
||||
|
||||
#region Click Event
|
||||
|
||||
public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent(nameof(Click), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VertexControl));
|
||||
|
||||
public event RoutedEventHandler Click
|
||||
{
|
||||
add { AddHandler(ClickEvent, value); }
|
||||
remove { RemoveHandler(ClickEvent, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Click Event
|
||||
|
||||
#region ChangeMonitor class
|
||||
|
||||
|
@ -259,9 +270,12 @@ namespace GraphX.Controls
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion ChangeMonitor class
|
||||
|
||||
#elif METRO
|
||||
|
||||
#region Attached property tracer
|
||||
|
||||
private static readonly DependencyProperty TestXProperty =
|
||||
DependencyProperty.Register("TestX", typeof(double), typeof(VertexControl), new PropertyMetadata(0, Testxchanged));
|
||||
|
||||
|
@ -281,7 +295,8 @@ namespace GraphX.Controls
|
|||
if (vc != null)
|
||||
vc.OnPositionChanged();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion Attached property tracer
|
||||
|
||||
/// <summary>
|
||||
/// Create vertex visual control
|
||||
|
@ -327,18 +342,22 @@ namespace GraphX.Controls
|
|||
if (EventOptions.MouseClickEnabled) PointerPressed += VertexControl_Down;
|
||||
else PointerPressed -= VertexControl_Down;
|
||||
break;
|
||||
|
||||
case EventType.MouseDoubleClick:
|
||||
// if (EventOptions.MouseDoubleClickEnabled) Poi += VertexControl_MouseDoubleClick;
|
||||
// else MouseDoubleClick -= VertexControl_MouseDoubleClick;
|
||||
break;
|
||||
|
||||
case EventType.MouseMove:
|
||||
if (EventOptions.MouseMoveEnabled) PointerMoved += VertexControl_MouseMove;
|
||||
else PointerMoved -= VertexControl_MouseMove;
|
||||
break;
|
||||
|
||||
case EventType.MouseEnter:
|
||||
if (EventOptions.MouseEnterEnabled) PointerEntered += VertexControl_MouseEnter;
|
||||
else PointerEntered -= VertexControl_MouseEnter;
|
||||
break;
|
||||
|
||||
case EventType.MouseLeave:
|
||||
if (EventOptions.MouseLeaveEnabled) PointerExited += VertexControl_MouseLeave;
|
||||
else PointerExited -= VertexControl_MouseLeave;
|
||||
|
@ -355,14 +374,14 @@ namespace GraphX.Controls
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root element which hosts VCPs so you can add them at runtime. Requires Panel-descendant template item defined named PART_vcproot.
|
||||
/// </summary>
|
||||
public Panel VCPRoot { get; protected set; }
|
||||
|
||||
#if WPF
|
||||
public
|
||||
|
||||
public
|
||||
#elif METRO
|
||||
protected
|
||||
#endif
|
||||
|
@ -377,7 +396,7 @@ namespace GraphX.Controls
|
|||
|
||||
if (VertexLabelControl != null)
|
||||
{
|
||||
if(ShowLabel) VertexLabelControl.Show(); else VertexLabelControl.Hide();
|
||||
if (ShowLabel) VertexLabelControl.Show(); else VertexLabelControl.Hide();
|
||||
UpdateLayout();
|
||||
VertexLabelControl.UpdatePosition();
|
||||
}
|
||||
|
@ -387,31 +406,29 @@ namespace GraphX.Controls
|
|||
throw new GX_InvalidDataException("Vertex connection points in VertexControl template must have unique Id!");
|
||||
}
|
||||
|
||||
#region Events handling
|
||||
#region Events handling
|
||||
|
||||
|
||||
|
||||
void VertexControl_MouseLeave(object sender, MouseEventArgs e)
|
||||
private void VertexControl_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexMouseLeave(this, e);
|
||||
VisualStateManager.GoToState(this, "PointerLeave", true);
|
||||
}
|
||||
|
||||
void VertexControl_MouseEnter(object sender, MouseEventArgs e)
|
||||
private void VertexControl_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexMouseEnter(this, e);
|
||||
VisualStateManager.GoToState(this, "PointerOver", true);
|
||||
}
|
||||
|
||||
void VertexControl_MouseMove(object sender, MouseEventArgs e)
|
||||
private void VertexControl_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (RootArea != null)
|
||||
RootArea.OnVertexMouseMove(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Events handling
|
||||
|
||||
/// <summary>
|
||||
/// Cleans all potential memory-holding code
|
||||
|
@ -440,6 +457,6 @@ namespace GraphX.Controls
|
|||
public T GetDataVertex<T>() where T : IGraphXVertex
|
||||
{
|
||||
return (T)Vertex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ using System.Linq;
|
|||
#if WPF
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using USize = System.Windows.Size;
|
||||
using Point = System.Windows.Point;
|
||||
#elif METRO
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
@ -12,6 +14,7 @@ using Windows.Foundation;
|
|||
using GraphX.Controls.Models;
|
||||
using GraphX.PCL.Common;
|
||||
using GraphX.PCL.Common.Enums;
|
||||
using Rect = GraphX.Measure.Rect;
|
||||
|
||||
namespace GraphX.Controls
|
||||
{
|
||||
|
@ -232,6 +235,17 @@ namespace GraphX.Controls
|
|||
return result;
|
||||
}
|
||||
|
||||
public IVertexConnectionPoint GetConnectionPointAt(Point position)
|
||||
{
|
||||
Measure(new USize(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
return VertexConnectionPointsList.FirstOrDefault(a =>
|
||||
{
|
||||
var rect = new Rect(a.RectangularSize.X, a.RectangularSize.Y, a.RectangularSize.Width, a.RectangularSize.Height);
|
||||
return rect.Contains(position.ToGraphX());
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method. Attaches label to control
|
||||
/// </summary>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#if WPF
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.ComponentModel;
|
||||
|
||||
#elif METRO
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
@ -49,6 +52,7 @@ namespace GraphX.Controls
|
|||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
var childCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
|
@ -66,6 +70,5 @@ namespace GraphX.Controls
|
|||
return DesignMode.DesignModeEnabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,11 +10,11 @@
|
|||
/// Gets or sets source vertex
|
||||
/// </summary>
|
||||
new TVertex Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets target vertex
|
||||
/// </summary>
|
||||
new TVertex Target { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -26,33 +26,36 @@
|
|||
/// Gets or sets source vertex
|
||||
/// </summary>
|
||||
new IGraphXVertex Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets target vertex
|
||||
/// </summary>
|
||||
new IGraphXVertex Target { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core edge data interface
|
||||
/// </summary>
|
||||
public interface IGraphXCommonEdge: IIdentifiableGraphDataObject, IRoutingInfo
|
||||
public interface IGraphXCommonEdge : IIdentifiableGraphDataObject, IRoutingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets if edge is self-looped
|
||||
/// </summary>
|
||||
bool IsSelfLoop { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional parameter to bind edge to static vertex connection point
|
||||
/// </summary>
|
||||
int? SourceConnectionPointId { get; }
|
||||
int? SourceConnectionPointId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional parameter to bind edge to static vertex connection point
|
||||
/// </summary>
|
||||
int? TargetConnectionPointId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the calculated routing path points.
|
||||
/// </summary>
|
||||
bool ReversePath { get; set; }}
|
||||
}
|
||||
int? TargetConnectionPointId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the calculated routing path points.
|
||||
/// </summary>
|
||||
bool ReversePath { get; set; }
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче