IsPortless 画线

This commit is contained in:
艾竹
2023-01-27 20:10:17 +08:00
parent 72e3efb052
commit e8bd6faa21
15 changed files with 197 additions and 49 deletions

View File

@@ -56,7 +56,7 @@ namespace AIStudio.Wpf.DiagramDesigner.Demo
Children=new List<MenuItemViewModel>
{
new MenuItemViewModel(){Title = "Svg"},
new MenuItemViewModel(){Title = "Portless"},
new MenuItemViewModel(){Title = "PortlessLinks"},
}
},
new MenuItemViewModel(){Title = "Links",
@@ -87,13 +87,13 @@ namespace AIStudio.Wpf.DiagramDesigner.Demo
},
new MenuItemViewModel(){Title = "Algorithms",
Children=new List<MenuItemViewModel>
{
{
new MenuItemViewModel(){Title = "ReconnectLinksToClosestPorts"},
}
},
new MenuItemViewModel(){Title = "Animations",
Children=new List<MenuItemViewModel>
{
{
new MenuItemViewModel(){Title = "PathAnimation"},
new MenuItemViewModel(){Title = "LineAnimation"},
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels
{
class PortlessLinksViewModel : BaseViewModel
{
public PortlessLinksViewModel()
{
Title = "Portless Links";
Info = "Starting from 2.0, you can create links between nodes directly! " +
"All you need to specify is the shape of your nodes in order to calculate the connection points.";
DiagramViewModel = new DiagramViewModel();
DiagramViewModel.PageSizeType = PageSizeType.Custom;
DiagramViewModel.PageSize = new Size(double.NaN, double.NaN);
DiagramViewModel.ColorViewModel = new ColorViewModel();
DiagramViewModel.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange;
DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 50, Top = 50, Text = "1" };
DiagramViewModel.DirectAddItemCommand.Execute(node1);
DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 300, Top = 50, Text = "2" };
DiagramViewModel.DirectAddItemCommand.Execute(node2);
DefaultDesignerItemViewModel node3 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 300, Top = 300, Text = "3" };
DiagramViewModel.DirectAddItemCommand.Execute(node3);
DefaultDesignerItemViewModel node4 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 50, Top = 300, Text = "4" };
DiagramViewModel.DirectAddItemCommand.Execute(node4);
ConnectionViewModel connector1 = new ConnectionViewModel(DiagramViewModel, node1.PortlessConnector, node2.PortlessConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal);
DiagramViewModel.DirectAddItemCommand.Execute(connector1);
ConnectionViewModel connector2 = new ConnectionViewModel(DiagramViewModel, node2.PortlessConnector, node3.RightConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal);
DiagramViewModel.DirectAddItemCommand.Execute(connector2);
ConnectionViewModel connector3 = new ConnectionViewModel(DiagramViewModel, node3.LeftConnector, node4.PortlessConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal);
DiagramViewModel.DirectAddItemCommand.Execute(connector3);
DiagramViewModel.ClearSelectedItemsCommand.Execute(null);
}
}
}

View File

@@ -7,9 +7,18 @@
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Demo.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type dd:GroupDesignerItemViewModel}">
<Grid IsHitTestVisible="{Binding IsHitTestVisible}">
<TextBlock Text="Group"/>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<!-- Diagram Control -->
<dd:DiagramControl x:Name="diagram" DataContext="{Binding DiagramViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<dd:DiagramControl x:Name="diagram" DataContext="{Binding DiagramViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
</dd:DiagramControl>
<controls:TitleControl/>
</Grid>

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Demo.Views.PortlessLinksView"
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:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Demo.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<!-- Diagram Control -->
<dd:DiagramControl x:Name="diagram" DataContext="{Binding DiagramViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<controls:TitleControl/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AIStudio.Wpf.DiagramDesigner.Demo.Views
{
/// <summary>
/// PortlessLinksView.xaml 的交互逻辑
/// </summary>
public partial class PortlessLinksView : UserControl
{
public PortlessLinksView()
{
InitializeComponent();
}
}
}

View File

@@ -21,7 +21,7 @@
SmallChange="0.1"
LargeChange="0.1"
Width="200"
HorizontalAlignment="Right"
HorizontalAlignment="Left"
VerticalAlignment="Top"/>
<controls:TitleControl/>

View File

@@ -17,22 +17,40 @@ namespace AIStudio.Wpf.DiagramDesigner
point = new PointBase(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio - connector.ConnectorWidth / 2,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio - connector.ConnectorHeight / 2);
}
else if (connector.IsPortless)
{
point = connector.DataItem?.GetBounds().Center?? connector.MiddlePosition;
}
else
{
switch (connector.Orientation)
{
case ConnectorOrientation.Left:
point = new PointBase(connector.DataItem.Left - connector.ConnectorWidth / 2, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2) - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.TopLeft:
point = new PointBase(connector.DataItem.Left - connector.ConnectorWidth / 2, connector.DataItem.Top - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Top:
point = new PointBase(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2) - connector.ConnectorWidth / 2, connector.DataItem.Top - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Bottom:
point = new PointBase(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2) - connector.ConnectorWidth / 2, (connector.DataItem.Top + connector.DataItem.ItemHeight) - connector.ConnectorHeight / 2);
case ConnectorOrientation.TopRight:
point = new PointBase(connector.DataItem.Left + connector.DataItem.ItemWidth - connector.ConnectorWidth / 2, connector.DataItem.Top - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Right:
point = new PointBase(connector.DataItem.Left + connector.DataItem.ItemWidth - connector.ConnectorWidth / 2, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2) - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Left:
point = new PointBase(connector.DataItem.Left - connector.ConnectorWidth / 2, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2) - connector.ConnectorHeight / 2);
case ConnectorOrientation.BottomRight:
point = new PointBase(connector.DataItem.Left + connector.DataItem.ItemWidth - connector.ConnectorWidth / 2, connector.DataItem.Top + connector.DataItem.ItemHeight - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Bottom:
point = new PointBase(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2) - connector.ConnectorWidth / 2, connector.DataItem.Top + connector.DataItem.ItemHeight - connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.BottomLeft:
point = new PointBase(connector.DataItem.Left - connector.ConnectorWidth / 2, connector.DataItem.Top + connector.DataItem.ItemHeight - connector.ConnectorHeight / 2);
break;
default:
point = new PointBase(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2) - connector.ConnectorWidth / 2, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2) - connector.ConnectorHeight / 2);
break;
}
}

View File

@@ -31,6 +31,7 @@
VerticalContentAlignment="{Binding FontViewModel.VerticalAlignment}"
TextBlock.LineHeight="{Binding FontViewModel.LineHeight}"
AcceptsReturn="True"
IsHitTestVisible="False"
s:ControlAttachProperty.Watermark="{Binding Path=(s:ControlAttachProperty.Watermark),RelativeSource={RelativeSource AncestorType={x:Type s:TextControl}}}"
Style="{StaticResource WaterTextBoxWithEffect}" IsReadOnly="True">

View File

@@ -18,15 +18,15 @@ namespace AIStudio.Wpf.DiagramDesigner
/// </summary>
public partial class TextControl : UserControl
{
public static readonly DependencyProperty DoubleEditProperty = DependencyProperty.Register(
nameof(DoubleEdit), typeof(bool), typeof(TextControl), new FrameworkPropertyMetadata(
true));
//public static readonly DependencyProperty DoubleEditProperty = DependencyProperty.Register(
// nameof(DoubleEdit), typeof(bool), typeof(TextControl), new FrameworkPropertyMetadata(
// true));
public bool DoubleEdit
{
get => (bool)GetValue(DoubleEditProperty);
set => SetValue(DoubleEditProperty, value);
}
//public bool DoubleEdit
//{
// get => (bool)GetValue(DoubleEditProperty);
// set => SetValue(DoubleEditProperty, value);
//}
public TextControl()
{
@@ -69,13 +69,7 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
}
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
if (DoubleEdit == false)
else if (e.PropertyName == "EditText")
{
PART_ShowText.Visibility = Visibility.Visible;
PART_TextBlock.Visibility = Visibility.Collapsed;
@@ -87,21 +81,37 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
base.OnPreviewMouseDoubleClick(e);
//protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
//{
// base.OnPreviewMouseDown(e);
if (DoubleEdit == true)
{
PART_ShowText.Visibility = Visibility.Visible;
PART_TextBlock.Visibility = Visibility.Collapsed;
PART_ShowText.Focus();
if (!string.IsNullOrEmpty(PART_ShowText.Text))
{
PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
}
}
}
// if (DoubleEdit == false)
// {
// PART_ShowText.Visibility = Visibility.Visible;
// PART_TextBlock.Visibility = Visibility.Collapsed;
// PART_ShowText.Focus();
// if (!string.IsNullOrEmpty(PART_ShowText.Text))
// {
// PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
// }
// }
//}
//protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
//{
// base.OnPreviewMouseDoubleClick(e);
// if (DoubleEdit == true)
// {
// PART_ShowText.Visibility = Visibility.Visible;
// PART_TextBlock.Visibility = Visibility.Collapsed;
// PART_ShowText.Focus();
// if (!string.IsNullOrEmpty(PART_ShowText.Text))
// {
// PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
// }
// }
//}
}
public class ControlAttachProperty

View File

@@ -370,7 +370,7 @@ namespace AIStudio.Wpf.DiagramDesigner
RaisePropertyChanged(nameof(IsFullConnection));
}
public bool IsPortless => SourceConnectorInfo?.DataItem?.Connectors?.Count() == 0;
public bool IsPortless => SourceConnectorInfo.IsPortless || SinkConnectorInfoFully?.IsPortless == true;
#endregion
#region
@@ -607,9 +607,9 @@ namespace AIStudio.Wpf.DiagramDesigner
{
if (SourceConnectorInfo.DataItem == null || (IsFullConnection && SinkConnectorInfoFully.DataItem == null))
return (null, null);
var sourceCenter = SourceConnectorInfo.DataItem.GetBounds().Center;
var targetCenter = SinkConnectorInfoFully?.DataItem?.GetBounds().Center ?? OnGoingPosition;
var sourceCenter = SourceConnectorInfo.IsPortless ? SourceConnectorInfo.DataItem.GetBounds().Center : SourceConnectorInfo.MiddlePosition;
var targetCenter = SinkConnectorInfoFully?.IsPortless == true ? SinkConnectorInfoFully?.DataItem?.GetBounds().Center ?? OnGoingPosition : SinkConnectorInfoFully?.MiddlePosition ?? OnGoingPosition;
var firstPt = route.Length > 0 ? route[0] : targetCenter;
var secondPt = route.Length > 0 ? route[0] : sourceCenter;
var sourceLine = new LineBase(firstPt, sourceCenter);
@@ -618,7 +618,8 @@ namespace AIStudio.Wpf.DiagramDesigner
var targetIntersections = SinkConnectorInfoFully.DataItem.GetShape()?.GetIntersectionsWithLine(targetLine) ?? new PointBase[] { OnGoingPosition };
var sourceIntersection = GetClosestPointTo(sourceIntersections, firstPt);
var targetIntersection = GetClosestPointTo(targetIntersections, secondPt);
return (sourceIntersection ?? sourceCenter, targetIntersection ?? targetCenter);
return (sourceIntersection ?? sourceCenter,targetIntersection ?? targetCenter);
}
else
{
@@ -626,6 +627,8 @@ namespace AIStudio.Wpf.DiagramDesigner
var target = SinkConnectorInfo.MiddlePosition;// GetPortPositionBasedOnAlignment(SinkConnectorInfoFully, ColorViewModel.RightArrowSizeStyle);
return (source, target);
}
}
private PointBase? GetPortPositionBasedOnAlignment(ConnectorInfoBase port, ArrowSizeStyle marker)

View File

@@ -143,6 +143,11 @@ namespace AIStudio.Wpf.DiagramDesigner
get; set;
}
public bool IsPortless
{
get; set;
}
public ValueTypePoint _valueTypePoint;
public ValueTypePoint ValueTypePoint
{

View File

@@ -64,10 +64,10 @@ namespace AIStudio.Wpf.DiagramDesigner
protected virtual void InitConnector()
{
connectors.Add(new FullyCreatedConnectorInfo(this, ConnectorOrientation.Top));
connectors.Add(new FullyCreatedConnectorInfo(this, ConnectorOrientation.Bottom));
connectors.Add(new FullyCreatedConnectorInfo(this, ConnectorOrientation.Left));
connectors.Add(new FullyCreatedConnectorInfo(this, ConnectorOrientation.Right));
connectors.Add(new FullyCreatedConnectorInfo(this.Root, this, ConnectorOrientation.Top));
connectors.Add(new FullyCreatedConnectorInfo(this.Root, this, ConnectorOrientation.Bottom));
connectors.Add(new FullyCreatedConnectorInfo(this.Root, this, ConnectorOrientation.Left));
connectors.Add(new FullyCreatedConnectorInfo(this.Root, this, ConnectorOrientation.Right));
}
#region
@@ -135,6 +135,18 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
private FullyCreatedConnectorInfo _portlessConnector;
public FullyCreatedConnectorInfo PortlessConnector
{
get
{
if (_portlessConnector == null)
_portlessConnector = new FullyCreatedConnectorInfo(this.Root, this, ConnectorOrientation.None) { IsPortless = true };
return _portlessConnector;
}
}
public Style ConnectorStyle
{
get; set;

View File

@@ -191,6 +191,8 @@ namespace AIStudio.Wpf.DiagramDesigner
if (IsReadOnly == true) return;
ShowText = true;
RaisePropertyChanged("EditText");
}
}
}