You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1101 lines
38 KiB
C#
1101 lines
38 KiB
C#
// ***********************************************************************
|
|
// Assembly : Construction
|
|
// Author : flythink
|
|
// Created : 06-05-2020
|
|
//
|
|
// Last Modified By : flythink
|
|
// Last Modified On : 09-01-2020
|
|
// ***********************************************************************
|
|
// <copyright file="MatchColumnControl.cs" company="jindongfang">
|
|
// Copyright (c) jindongfang. All rights reserved.
|
|
// </copyright>
|
|
// <summary></summary>
|
|
// ***********************************************************************
|
|
|
|
namespace WellWorkDataUI.CustomControls
|
|
{
|
|
using DevExpress.Diagram.Core;
|
|
using DevExpress.Diagram.Core.Native;
|
|
using DevExpress.Utils;
|
|
using DevExpress.Utils.Svg;
|
|
using DevExpress.XtraDiagram;
|
|
using Fk.Utils;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
|
|
/// <summary>
|
|
/// 导入数据时匹配列控件
|
|
/// </summary>
|
|
public partial class MatchColumnControl : DevExpress.XtraEditors.XtraUserControl
|
|
{
|
|
private static readonly Color[] Colors = new Color[]
|
|
{
|
|
Color.FromArgb(243, 159, 68),
|
|
//Color.FromArgb(255, 131, 96), Color.FromArgb(125, 206, 130),
|
|
//Color.FromArgb(106, 15, 73), Color.FromArgb(0, 255, 245),
|
|
//Color.FromArgb(254, 95, 85), Color.FromArgb(13, 59, 102),
|
|
//Color.FromArgb(240, 182, 127), Color.FromArgb(244, 211, 94),
|
|
//Color.FromArgb(238, 150, 75), Color.FromArgb(180, 122, 234),
|
|
};
|
|
|
|
private int colorIndex = 0;
|
|
|
|
private DiagramContainer fromContainer;
|
|
|
|
private Orientation orientation = Orientation.Vertical;
|
|
|
|
private SlowDownTimer timer = new SlowDownTimer(200);
|
|
|
|
private DiagramContainer toContainer;
|
|
|
|
private CustomDiagramShape lastSelection;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="MatchColumnControl" /> class.
|
|
/// </summary>
|
|
public MatchColumnControl()
|
|
{
|
|
this.InitializeComponent();
|
|
|
|
// diagramControl1.OptionsView.ScrollMargin = new Padding(Int32.MaxValue);
|
|
this.diagramControl.Margin = new Padding(0);
|
|
this.diagramControl.Padding = new Padding(0);
|
|
this.diagramControl.AddingNewItem += this.DiagramControl1_AddingNewItem;
|
|
this.diagramControl.ItemsDeleting += this.DiagramControl1_ItemsDeleting;
|
|
this.diagramControl.ConnectionChanged += this.DiagramControl1_ConnectionChanged;
|
|
|
|
this.diagramControl.OptionsBehavior.ActiveTool = new CustomDiagramTool();
|
|
|
|
this.diagramControl.SelectionChanged += this.DiagramControl_SelectionChanged;
|
|
|
|
this.CreateContainer();
|
|
}
|
|
|
|
private void DiagramControl_SelectionChanged(object sender, DiagramSelectionChangedEventArgs e)
|
|
{
|
|
if (this.diagramControl.SelectedItems.FirstOrDefault() is CustomDiagramShape shape)
|
|
{
|
|
if (shape.IsBegin)
|
|
{
|
|
this.lastSelection = shape;
|
|
}
|
|
else if (this.lastSelection?.IsBegin == true)
|
|
{
|
|
this.ConnectShape(this.lastSelection, shape);
|
|
this.lastSelection = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the orientation.
|
|
/// </summary>
|
|
/// <value>The orientation.</value>
|
|
public Orientation Orientation
|
|
{
|
|
get => this.orientation;
|
|
set
|
|
{
|
|
this.orientation = value;
|
|
this.MoveContainer();
|
|
}
|
|
}
|
|
|
|
private float ShapeHeight => 20;
|
|
|
|
private float ShapeHeightSpace => this.ShapeHeight + 3;
|
|
|
|
public float ShapeWidth { get; set; } = 120;
|
|
|
|
private float ShapeWidthSpace => this.ShapeWidth + 3;
|
|
|
|
/// <summary>
|
|
/// Adds the left item.
|
|
/// </summary>
|
|
/// <param name="name">The name.</param>
|
|
/// <param name="tag">The tag.</param>
|
|
/// <param name="multi">if set to <c>true</c> [multi].</param>
|
|
public void AddFromItem(string name, object tag = null, bool multi = false, bool must = false)
|
|
{
|
|
this.CreateBeginShape(BasicShapes.Rectangle, name, tag, multi, must);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the right item.
|
|
/// </summary>
|
|
/// <param name="name">The name.</param>
|
|
/// <param name="tag">The tag.</param>
|
|
public void AddToItem(string name, object tag = null)
|
|
{
|
|
this.CreateEndShape(BasicShapes.Rectangle, name, tag);
|
|
}
|
|
|
|
/// <summary>
|
|
/// UpdateMatch
|
|
/// </summary>
|
|
public void UpdateMatch()
|
|
{
|
|
this.MoveContainer();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears this instance.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
this.fromContainer.Items.Clear();
|
|
this.toContainer.Items.Clear();
|
|
|
|
this.ClearConnection();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the connection.
|
|
/// </summary>
|
|
public void ClearConnection()
|
|
{
|
|
List<DiagramConnector> connectionList = this.diagramControl.Items.OfType<DiagramConnector>().ToList();
|
|
|
|
foreach (DiagramConnector item in connectionList)
|
|
{
|
|
this.diagramControl.Items.Remove(item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects the specified from item.
|
|
/// </summary>
|
|
/// <param name="fromItem">From item.</param>
|
|
/// <param name="toItem">To item.</param>
|
|
public void Connect(MatchItem fromItem, MatchItem toItem)
|
|
{
|
|
CustomDiagramShape a = fromItem.Shape;
|
|
CustomDiagramShape b = toItem.Shape;
|
|
|
|
this.ConnectShape(a, b);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects the specified from name.
|
|
/// </summary>
|
|
/// <param name="fromName">From name.</param>
|
|
/// <param name="toName">To name.</param>
|
|
public void Connect(string fromName, string toName)
|
|
{
|
|
CustomDiagramShape a = this.fromContainer.Items.OfType<CustomDiagramShape>().FirstOrDefault(r => r.Content == fromName);
|
|
CustomDiagramShape b = this.toContainer.Items.OfType<CustomDiagramShape>().FirstOrDefault(r => r.Content == fromName);
|
|
|
|
this.ConnectShape(a, b);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the container.
|
|
/// </summary>
|
|
public void CreateContainer()
|
|
{
|
|
this.fromContainer = this.CreateContainer(CustomContainers.Empty, new RectangleF(0, 0, 500, 2000));
|
|
this.toContainer = this.CreateContainer(CustomContainers.Empty, new RectangleF(300, 0, 500, 2000));
|
|
|
|
this.fromContainer.Padding = this.toContainer.Padding = new Padding(0);
|
|
|
|
this.diagramControl.Items.Add(this.fromContainer);
|
|
this.diagramControl.Items.Add(this.toContainer);
|
|
|
|
this.MoveContainer();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the test data.
|
|
/// </summary>
|
|
public void CreateTestData()
|
|
{
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
this.AddFromItem($"数据库字段{i + 1}", null, true);
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
this.AddToItem($"文件字段{i + 1}", null);
|
|
}
|
|
|
|
this.UpdateMatch();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets from items.
|
|
/// </summary>
|
|
/// <returns>IEnumerable<MatchItem>.</returns>
|
|
public IEnumerable<MatchItem> GetFromItems()
|
|
{
|
|
for (int i = 0; i < this.fromContainer.Items.Count; i++)
|
|
{
|
|
CustomDiagramShape item = this.fromContainer.Items[i] as CustomDiagramShape;
|
|
|
|
yield return new MatchFromItem
|
|
{
|
|
Shape = item,
|
|
Name = item.Content,
|
|
Index = i,
|
|
Tag = item.Tag,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the matches.
|
|
/// </summary>
|
|
/// <returns>List<MatchLeftItem>.</returns>
|
|
public List<MatchFromItem> GetMatches()
|
|
{
|
|
List<MatchFromItem> list = new List<MatchFromItem>();
|
|
|
|
for (int i = 0; i < this.fromContainer.Items.Count; i++)
|
|
{
|
|
CustomDiagramShape item = this.fromContainer.Items[i] as CustomDiagramShape;
|
|
|
|
MatchFromItem lhs = new MatchFromItem
|
|
{
|
|
Shape = item,
|
|
Name = item.Content,
|
|
Index = i,
|
|
Tag = item.Tag,
|
|
};
|
|
|
|
foreach (IDiagramConnector conn in item.OutgoingConnectors)
|
|
{
|
|
if (conn.EndItem is CustomDiagramShape right)
|
|
{
|
|
MatchToItem rhs = new MatchToItem
|
|
{
|
|
Shape = right,
|
|
Name = right.Content,
|
|
Index = this.toContainer.Items.IndexOf(right),
|
|
Tag = right.Tag,
|
|
};
|
|
|
|
rhs.Connections.Add(lhs);
|
|
|
|
lhs.Connections.Add(rhs);
|
|
}
|
|
}
|
|
|
|
list.Add(lhs);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets to items.
|
|
/// </summary>
|
|
/// <returns>IEnumerable<MatchItem>.</returns>
|
|
public IEnumerable<MatchItem> GetToItems()
|
|
{
|
|
for (int i = 0; i < this.toContainer.Items.Count; i++)
|
|
{
|
|
CustomDiagramShape item = this.toContainer.Items[i] as CustomDiagramShape;
|
|
|
|
yield return new MatchToItem
|
|
{
|
|
Shape = item,
|
|
Name = item.Content,
|
|
Index = i,
|
|
Tag = item.Tag,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises the <see cref="E:System.Windows.Forms.Control.ClientSizeChanged" /> event.
|
|
/// </summary>
|
|
/// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param>
|
|
protected override void OnClientSizeChanged(EventArgs e)
|
|
{
|
|
base.OnClientSizeChanged(e);
|
|
|
|
this.MoveContainer();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes a command key.
|
|
/// </summary>
|
|
/// <param name="msg">A <see cref="T:System.Windows.Forms.Message" />, passed by reference, that represents the window message to process.</param>
|
|
/// <param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys" /> values that represents the key to process.</param>
|
|
/// <returns><see langword="true" /> if the character was processed by the control; otherwise, <see langword="false" />.</returns>
|
|
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
|
{
|
|
void MoveView(Func<System.Windows.Point, System.Windows.Point> action)
|
|
{
|
|
LayersHostController controller = ((IDiagramControl)this.diagramControl).Controller.LayersHost.Controller;
|
|
|
|
System.Windows.Point pos = controller.VisibleArea.TopLeft;
|
|
|
|
pos = action(pos);
|
|
|
|
if (pos.X + controller.VisibleArea.Width > controller.Location.X + controller.Extent.Width)
|
|
{
|
|
pos.X = controller.Location.X + controller.Extent.Width - controller.VisibleArea.Width;
|
|
}
|
|
|
|
if (pos.X < controller.Location.X)
|
|
{
|
|
pos.X = controller.Location.X;
|
|
}
|
|
|
|
if (pos.Y + controller.VisibleArea.Height > controller.Location.Y + controller.Extent.Height)
|
|
{
|
|
pos.Y = controller.Location.Y + controller.Extent.Height - controller.VisibleArea.Height;
|
|
}
|
|
|
|
if (pos.Y < controller.Location.Y)
|
|
{
|
|
pos.Y = controller.Location.Y;
|
|
}
|
|
|
|
this.diagramControl.ScrollToPoint(pos, HorizontalAlignmentKind.Left, VerticalAlignmentKind.Top);
|
|
}
|
|
|
|
if (this.orientation == Orientation.Horizontal)
|
|
{
|
|
if (keyData == Keys.Right)
|
|
{
|
|
MoveView(
|
|
pos =>
|
|
{
|
|
pos.X += this.Width * 0.8f;
|
|
return pos;
|
|
});
|
|
}
|
|
|
|
if (keyData == Keys.Left)
|
|
{
|
|
MoveView(
|
|
pos =>
|
|
{
|
|
pos.X -= this.Width * 0.8f;
|
|
return pos;
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (keyData == Keys.Up)
|
|
{
|
|
MoveView(
|
|
pos =>
|
|
{
|
|
pos.Y -= this.Height * 0.8f;
|
|
return pos;
|
|
});
|
|
}
|
|
|
|
if (keyData == Keys.Down)
|
|
{
|
|
MoveView(
|
|
pos =>
|
|
{
|
|
pos.Y += this.Height * 0.8f;
|
|
return pos;
|
|
});
|
|
}
|
|
}
|
|
|
|
return base.ProcessCmdKey(ref msg, keyData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects the shape.
|
|
/// </summary>
|
|
/// <param name="a">a.</param>
|
|
/// <param name="b">The b.</param>
|
|
private void ConnectShape(CustomDiagramShape a, CustomDiagramShape b)
|
|
{
|
|
if (a != null && b != null)
|
|
{
|
|
CustomDiagramConnector c = new CustomDiagramConnector(ConnectorType.Straight, a, b);
|
|
|
|
b.Appearance.BackColor = a.Appearance.BackColor;
|
|
b.Appearance.ForeColor = a.Appearance.ForeColor;
|
|
c.Appearance.BorderColor = a.Appearance.BackColor;
|
|
|
|
this.diagramControl.Items.Add(c);
|
|
|
|
this.SortItemsOnce();
|
|
}
|
|
}
|
|
|
|
private void CreateBeginShape(ShapeDescription shape, string content, object tag, bool multi, bool must = false)
|
|
{
|
|
RectangleF bounds = this.GetShapeBounds(this.fromContainer.Items.Count);
|
|
|
|
CustomDiagramShape item = new CustomDiagramShape(shape, bounds, content, true);
|
|
|
|
item.CanCopy = false;
|
|
item.CanEdit = false;
|
|
item.CanDelete = false;
|
|
item.CanMove = false;
|
|
item.CanResize = false;
|
|
item.CanRotate = false;
|
|
//item.CanAttachConnectorEndPoint = false;
|
|
item.CanAttachMultiConnector = multi;
|
|
|
|
item.Appearance.BackColor = this.GetNextColor();
|
|
if (must)
|
|
{
|
|
item.Appearance.BackColor = Color.FromArgb(255, 90, 90);
|
|
}
|
|
item.Appearance.ForeColor = this.GetForeColor(item.Appearance.BackColor);
|
|
|
|
item.CreateBeginPoints(this.orientation);
|
|
|
|
item.Tag = tag;
|
|
|
|
this.fromContainer.Items.Add(item);
|
|
}
|
|
|
|
private DiagramContainer CreateContainer(ContainerShapeDescription shape, RectangleF bounds)
|
|
{
|
|
return new DiagramContainer(bounds)
|
|
{
|
|
Shape = shape,
|
|
CanSelect = false,
|
|
CanMove = false,
|
|
CanResize = false,
|
|
CanDelete = false,
|
|
CanCopy = false,
|
|
CanAttachConnectorBeginPoint = false,
|
|
CanAttachConnectorEndPoint = false,
|
|
};
|
|
}
|
|
|
|
private void CreateEndShape(ShapeDescription shape, string content, object tag)
|
|
{
|
|
RectangleF bounds = this.GetShapeBounds(this.toContainer.Items.Count);
|
|
|
|
CustomDiagramShape item = new CustomDiagramShape(shape, bounds, content, false);
|
|
|
|
item.CanCopy = false;
|
|
item.CanEdit = false;
|
|
item.CanDelete = false;
|
|
item.CanMove = false;
|
|
item.CanResize = false;
|
|
item.CanRotate = false;
|
|
//item.CanAttachConnectorBeginPoint = false;
|
|
|
|
item.CreateEndPoints(this.orientation);
|
|
item.Tag = tag;
|
|
|
|
this.toContainer.Items.Add(item);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Diagrams the control1_ adding new item.
|
|
/// </summary>
|
|
/// <param name="sender">The sender.</param>
|
|
/// <param name="e">The e.</param>
|
|
private void DiagramControl1_AddingNewItem(object sender, DiagramAddingNewItemEventArgs e)
|
|
{
|
|
if (e.Item is CustomDiagramConnector dc)
|
|
{
|
|
CustomDiagramShape shape1 = dc.BeginItem as CustomDiagramShape;
|
|
CustomDiagramShape shape2 = dc.EndItem as CustomDiagramShape;
|
|
|
|
if (shape1 != null && shape2 != null && shape1.IsBegin != shape2.IsBegin)
|
|
{
|
|
CustomDiagramShape left = shape1.IsBegin ? shape1 : shape2;
|
|
CustomDiagramShape right = !shape1.IsBegin ? shape1 : shape2;
|
|
|
|
if (left.CanAttachMultiConnector && this.diagramControl.SelectedItems.Contains(right))
|
|
{
|
|
CustomDiagramConnector[] array = this.diagramControl.SelectedItems.OfType<CustomDiagramShape>().Select(
|
|
r =>
|
|
{
|
|
CustomDiagramConnector c = new CustomDiagramConnector(ConnectorType.Straight, left, r);
|
|
|
|
r.Appearance.BackColor = left.Appearance.BackColor;
|
|
r.Appearance.ForeColor = left.Appearance.ForeColor;
|
|
c.Appearance.BorderColor = left.Appearance.BackColor;
|
|
return c;
|
|
}).ToArray();
|
|
|
|
this.diagramControl.Items.AddRange(array);
|
|
}
|
|
else
|
|
{
|
|
CustomDiagramConnector c = new CustomDiagramConnector(ConnectorType.Straight, left, right);
|
|
|
|
right.Appearance.BackColor = left.Appearance.BackColor;
|
|
right.Appearance.ForeColor = left.Appearance.ForeColor;
|
|
c.Appearance.BorderColor = left.Appearance.BackColor;
|
|
|
|
this.diagramControl.Items.Add(c);
|
|
}
|
|
|
|
this.SortItemsOnce();
|
|
}
|
|
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
private void DiagramControl1_ConnectionChanged(object sender, DiagramConnectionChangedEventArgs e)
|
|
{
|
|
DiagramConnector dc = e.Connector;
|
|
|
|
if (e.OldItem == e.NewItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (dc.BeginItem is DiagramShape left && dc.EndItem is DiagramShape right)
|
|
{
|
|
right.Appearance.BackColor = left.Appearance.BackColor;
|
|
right.Appearance.ForeColor = left.Appearance.ForeColor;
|
|
dc.Appearance.BorderColor = left.Appearance.BackColor;
|
|
e.OldItem?.Appearance.Reset();
|
|
|
|
this.SortItemsOnce();
|
|
}
|
|
else
|
|
{
|
|
dc.EndItem = e.OldItem;
|
|
}
|
|
}
|
|
|
|
private void DiagramControl1_CustomDrawBackground(object sender, CustomDrawBackgroundEventArgs e)
|
|
{
|
|
using (SolidBrush brush = new SolidBrush(SkinHelper.CurrentBackground))
|
|
{
|
|
e.Graphics.FillRectangle(brush, e.TotalBounds);
|
|
}
|
|
}
|
|
|
|
private void DiagramControl1_ItemsDeleting(object sender, DiagramItemsDeletingEventArgs e)
|
|
{
|
|
foreach (DiagramItem item in e.Items)
|
|
{
|
|
if (item is CustomDiagramConnector dc && dc.EndItem is CustomDiagramShape end)
|
|
{
|
|
end.Appearance.Reset();
|
|
}
|
|
}
|
|
this.SortItemsOnce();
|
|
}
|
|
|
|
private void DiagramControl1_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
this.diagramControl.AlignPage(HorzAlignment.Near, VertAlignment.Top);
|
|
}
|
|
|
|
private Color GetForeColor(Color backColor, bool byBrightness = true)
|
|
{
|
|
float GetBrightness(Color c) => ((c.R * 0.299f) + (c.G * 0.587f) + (c.B * 0.114f)) / 256f;
|
|
Color GetInvertColor(Color c) => Color.FromArgb(c.ToArgb() ^ 0xffffff);
|
|
|
|
if (byBrightness)
|
|
{
|
|
return GetBrightness(backColor) < 0.55 ? Color.White : Color.Black;
|
|
}
|
|
|
|
return GetInvertColor(backColor);
|
|
}
|
|
|
|
private Color GetNextColor()
|
|
{
|
|
if (this.colorIndex >= Colors.Length)
|
|
{
|
|
this.colorIndex = 0;
|
|
}
|
|
|
|
return Colors[this.colorIndex++];
|
|
}
|
|
|
|
private RectangleF GetShapeBounds(int index)
|
|
{
|
|
if (this.orientation == Orientation.Vertical)
|
|
{
|
|
return new RectangleF(0, index * this.ShapeHeightSpace, this.ShapeWidth, this.ShapeHeight);
|
|
}
|
|
else
|
|
{
|
|
return new RectangleF(index * this.ShapeWidthSpace, 0, this.ShapeWidth, this.ShapeHeight);
|
|
}
|
|
}
|
|
|
|
private void MoveContainer()
|
|
{
|
|
if (this.fromContainer == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (this.toContainer == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int count = Math.Max(this.fromContainer.Items.Count, this.toContainer.Items.Count);
|
|
|
|
if (this.orientation == Orientation.Vertical)
|
|
{
|
|
var width = this.Size.Width;
|
|
var height = Math.Max(this.Size.Height, count * this.ShapeHeightSpace);
|
|
|
|
this.diagramControl.OptionsView.PageSize = new SizeF(width, height);
|
|
|
|
float w = width / 2.5f;
|
|
float h = height;
|
|
|
|
this.fromContainer.Bounds = new RectangleF(0, 0, w, h);
|
|
this.toContainer.Bounds = new RectangleF(w, 0, w, h);
|
|
}
|
|
else
|
|
{
|
|
var width = Math.Max(this.Size.Width, count * this.ShapeWidthSpace);
|
|
var height = this.Size.Height;
|
|
|
|
this.diagramControl.OptionsView.PageSize = new SizeF(width, height);
|
|
|
|
float w = width;
|
|
float h = height / 2.5f;
|
|
|
|
this.fromContainer.Bounds = new RectangleF(0, 0, w, h);
|
|
this.toContainer.Bounds = new RectangleF(0, h, w, h);
|
|
}
|
|
this.MoveItems();
|
|
}
|
|
|
|
private void MoveItems()
|
|
{
|
|
foreach (CustomDiagramShape item in this.fromContainer.Items)
|
|
{
|
|
item.CreateBeginPoints(this.orientation);
|
|
}
|
|
|
|
foreach (CustomDiagramShape item in this.toContainer.Items)
|
|
{
|
|
item.CreateEndPoints(this.orientation);
|
|
}
|
|
|
|
this.SortItemsOnce(true);
|
|
}
|
|
|
|
private void SortItemsOnce(bool immediate = false)
|
|
{
|
|
void SortLeft()
|
|
{
|
|
List<DiagramItem> list = this.fromContainer.Items.ToList();
|
|
|
|
int i = 0;
|
|
|
|
foreach (DiagramItem item in this.fromContainer.Items)
|
|
{
|
|
if (item.OutgoingConnectors.Any())
|
|
{
|
|
item.Bounds = this.GetShapeBounds(i++);
|
|
list.Remove(item);
|
|
}
|
|
}
|
|
|
|
foreach (DiagramItem left in list)
|
|
{
|
|
left.Bounds = this.GetShapeBounds(i++);
|
|
}
|
|
}
|
|
|
|
void SortRight()
|
|
{
|
|
List<DiagramItem> list = this.toContainer.Items.ToList();
|
|
|
|
int i = 0;
|
|
|
|
foreach (DiagramItem item in this.fromContainer.Items)
|
|
{
|
|
foreach (IDiagramConnector conn in item.GetAttachedConnectors())
|
|
{
|
|
if (conn.EndItem is CustomDiagramShape right && list.Contains(right))
|
|
{
|
|
right.Bounds = this.GetShapeBounds(i++);
|
|
|
|
list.Remove(right);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (DiagramItem right in list)
|
|
{
|
|
right.Bounds = this.GetShapeBounds(i++);
|
|
}
|
|
}
|
|
|
|
void SortItems()
|
|
{
|
|
this.diagramControl.BeginUpdate();
|
|
|
|
SortLeft();
|
|
SortRight();
|
|
|
|
this.diagramControl.EndUpdate();
|
|
}
|
|
|
|
if (immediate)
|
|
{
|
|
SortItems();
|
|
}
|
|
else
|
|
{
|
|
this.timer.Invoke(SortItems);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class MatchItem.
|
|
/// </summary>
|
|
public abstract class MatchItem
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the index.
|
|
/// </summary>
|
|
/// <value>The index.</value>
|
|
public int Index { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the name.
|
|
/// </summary>
|
|
/// <value>The name.</value>
|
|
public string Name { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the tag.
|
|
/// </summary>
|
|
/// <value>The tag.</value>
|
|
public object Tag { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Shape.
|
|
/// </summary>
|
|
/// <value>The Shape.</value>
|
|
internal CustomDiagramShape Shape { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class MatchLeftItem.
|
|
/// Implements the <see cref="DQ.Construction.NewLook.CustomControls.MatchItem" />
|
|
/// </summary>
|
|
/// <seealso cref="DQ.Construction.NewLook.CustomControls.MatchItem" />
|
|
public class MatchFromItem : MatchItem
|
|
{
|
|
/// <summary>
|
|
/// Gets the connections.
|
|
/// </summary>
|
|
/// <value>The connections.</value>
|
|
public List<MatchToItem> Connections { get; set; } = new List<MatchToItem>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class MatchRightItem.
|
|
/// Implements the <see cref="DQ.Construction.NewLook.CustomControls.MatchItem" />
|
|
/// </summary>
|
|
/// <seealso cref="DQ.Construction.NewLook.CustomControls.MatchItem" />
|
|
public class MatchToItem : MatchItem
|
|
{
|
|
/// <summary>
|
|
/// Gets the connections.
|
|
/// </summary>
|
|
/// <value>The connections.</value>
|
|
public List<MatchFromItem> Connections { get; } = new List<MatchFromItem>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class CustomContainers.
|
|
/// </summary>
|
|
public static class CustomContainers
|
|
{
|
|
/// <summary>
|
|
/// The empty
|
|
/// </summary>
|
|
public static readonly ContainerShapeDescription Empty = ContainerShapeDescription.Create(
|
|
"Empty",
|
|
"Empty",
|
|
CreateEmptyShape,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
DiagramShapeStyleId.Variant3,
|
|
true);
|
|
|
|
private static ShapeGeometry CreateEmptyShape(double width, double height, IEnumerable<double> parameters)
|
|
{
|
|
SvgGroup svgGroup = new SvgGroup();
|
|
|
|
return CreateSvgImage(width, height, svgGroup);
|
|
}
|
|
|
|
private static SvgImage CreateSvgImage(double width, double height, SvgElement childElement)
|
|
{
|
|
SvgRoot svgRoot = SvgRoot.Create(
|
|
new SvgElementProperties(),
|
|
null,
|
|
null,
|
|
new SvgUnit(width),
|
|
new SvgUnit(height));
|
|
svgRoot.Elements.Add(childElement);
|
|
return SvgImage.Create(svgRoot);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class CustomDiagramShape.
|
|
/// Implements the <see cref="DevExpress.XtraDiagram.DiagramShape" />
|
|
/// </summary>
|
|
/// <seealso cref="DevExpress.XtraDiagram.DiagramShape" />
|
|
public class CustomDiagramShape : DiagramShape
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CustomDiagramShape"/> class with the specified settings.
|
|
/// </summary>
|
|
/// <param name="shape">The shape kind. This object is used to initialize the <see cref="P:DevExpress.XtraDiagram.DiagramShape.Shape" /> property.</param>
|
|
/// <param name="bounds">A <see cref="T:System.Drawing.RectangleF" /> object that represents the shape bounds.</param>
|
|
/// <param name="content">The text displayed within the shape.</param>
|
|
/// <param name="isBegin">is begin.</param>
|
|
public CustomDiagramShape(ShapeDescription shape, RectangleF bounds, string content, bool isBegin)
|
|
: base(shape, bounds, content)
|
|
{
|
|
this.IsBegin = isBegin;
|
|
}
|
|
|
|
/// <summary>
|
|
/// IsBegin
|
|
/// </summary>
|
|
public bool IsBegin { get; set; }
|
|
|
|
/// <summary>
|
|
/// Specifies whether end-users can attach a connector's beginning point to the item.
|
|
/// </summary>
|
|
/// <value><b>true</b> to allow end-users to attach the begin point of a connector to the item; otherwise, <b>false</b>.</value>
|
|
public override bool? CanAttachConnectorBeginPoint
|
|
{
|
|
get
|
|
{
|
|
if (!this.CanAttachMultiConnector && this.OutgoingConnectors.Any())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return base.CanAttachConnectorBeginPoint;
|
|
}
|
|
set => base.CanAttachConnectorBeginPoint = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether this instance can attach multi connector.
|
|
/// </summary>
|
|
/// <value><c>true</c> if this instance can attach multi connector; otherwise, <c>false</c>.</value>
|
|
public bool CanAttachMultiConnector { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Creates the begin points.
|
|
/// </summary>
|
|
/// <param name="orientation">The orientation.</param>
|
|
public void CreateBeginPoints(Orientation orientation)
|
|
{
|
|
List<PointFloat> list = this.CreateOriginPoints();
|
|
|
|
if (orientation == Orientation.Vertical)
|
|
{
|
|
float maxX = list.Max(pt => pt.X);
|
|
this.ConnectionPoints = new PointCollection(list.Where(pt => pt.X == maxX).ToList());
|
|
}
|
|
else
|
|
{
|
|
float maxY = list.Max(pt => pt.Y);
|
|
this.ConnectionPoints = new PointCollection(list.Where(pt => pt.Y == maxY).ToList());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the end points.
|
|
/// </summary>
|
|
/// <param name="orientation">The orientation.</param>
|
|
public void CreateEndPoints(Orientation orientation)
|
|
{
|
|
List<PointFloat> list = this.CreateOriginPoints();
|
|
|
|
if (orientation == Orientation.Vertical)
|
|
{
|
|
float minX = list.Min(pt => pt.X);
|
|
|
|
this.ConnectionPoints = new PointCollection(list.Where(pt => pt.X == minX).ToList());
|
|
}
|
|
else
|
|
{
|
|
float minY = list.Min(pt => pt.Y);
|
|
|
|
this.ConnectionPoints = new PointCollection(list.Where(pt => pt.Y == minY).ToList());
|
|
}
|
|
}
|
|
|
|
private List<PointFloat> CreateOriginPoints()
|
|
{
|
|
List<PointFloat> list = new List<PointFloat>();
|
|
|
|
list.AddRange(
|
|
this.Shape.GetConnectionPoints(new System.Windows.Size(1d, 1d), this.Shape.DefaultParameters)
|
|
.Select(x => new PointFloat((float)x.X, (float)x.Y)));
|
|
|
|
return list;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class CustomDiagramConnector.
|
|
/// Implements the <see cref="DevExpress.XtraDiagram.DiagramConnector" />
|
|
/// </summary>
|
|
/// <seealso cref="DevExpress.XtraDiagram.DiagramConnector" />
|
|
public class CustomDiagramConnector : DiagramConnector
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CustomDiagramConnector" /> class.
|
|
/// </summary>
|
|
public CustomDiagramConnector()
|
|
: base()
|
|
{
|
|
this.Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CustomDiagramConnector"/> class with the specified settings.
|
|
/// </summary>
|
|
/// <param name="connectorType">The connector type. This value is used to initialize the <see cref="P:DevExpress.XtraDiagram.DiagramConnector.Type" /> property.</param>
|
|
public CustomDiagramConnector(ConnectorType connectorType)
|
|
: base(connectorType)
|
|
{
|
|
this.Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CustomDiagramConnector"/> class with the specified settings.
|
|
/// </summary>
|
|
/// <param name="connectorType">The connector type. This value is used to initialize the <see cref="P:DevExpress.XtraDiagram.DiagramConnector.Type" /> property.</param>
|
|
/// <param name="beginItem">The connector's starting item. This value is used to initialize the <see cref="P:DevExpress.XtraDiagram.DiagramConnector.BeginItem" /> property.</param>
|
|
/// <param name="endItem">The connector's ending item. This value is used to initialize the <see cref="P:DevExpress.XtraDiagram.DiagramConnector.EndItem" /> property.</param>
|
|
public CustomDiagramConnector(ConnectorType connectorType, DiagramItem beginItem, DiagramItem endItem)
|
|
: base(connectorType)
|
|
{
|
|
this.Init();
|
|
this.SetItems(beginItem, endItem);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the items.
|
|
/// </summary>
|
|
/// <param name="beginItem">The begin item.</param>
|
|
/// <param name="endItem">The end item.</param>
|
|
public new void SetItems(DiagramItem beginItem, DiagramItem endItem)
|
|
{
|
|
base.SetItems(beginItem, endItem);
|
|
|
|
this.BeginItemPointIndex = 0;
|
|
this.EndItemPointIndex = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the points.
|
|
/// </summary>
|
|
/// <param name="beginPoint">The begin point.</param>
|
|
/// <param name="endPoint">The end point.</param>
|
|
public new void SetPoints(PointF beginPoint, PointF endPoint)
|
|
{
|
|
base.SetPoints(beginPoint, endPoint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the points.
|
|
/// </summary>
|
|
/// <param name="beginPoint">The begin point.</param>
|
|
/// <param name="endPoint">The end point.</param>
|
|
public new void SetPoints(PointFloat beginPoint, PointFloat endPoint)
|
|
{
|
|
base.SetPoints(beginPoint, endPoint);
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
// this.CanDragEndPoint = false;
|
|
this.CanEdit = false;
|
|
this.CanCopy = false;
|
|
this.CanDragBeginPoint = false;
|
|
this.CanChangeRoute = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class CustomDiagramTool.
|
|
/// Implements the <see cref="DevExpress.Diagram.Core.FactoryConnectorTool" />
|
|
/// </summary>
|
|
/// <seealso cref="DevExpress.Diagram.Core.FactoryConnectorTool" />
|
|
public class CustomDiagramTool : FactoryConnectorTool
|
|
{
|
|
private PointerTool pointerTool = new PointerTool();
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CustomDiagramTool" /> class.
|
|
/// </summary>
|
|
public CustomDiagramTool()
|
|
: base("CustomDiagramTool", () => "CustomDiagramTool", CreateConnector)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the state of the active input.
|
|
/// </summary>
|
|
/// <param name="diagram">The diagram.</param>
|
|
/// <param name="item">The item.</param>
|
|
/// <param name="mouseArgs">The mouse arguments.</param>
|
|
/// <param name="previouslyCreatedItem">The previously created item.</param>
|
|
/// <returns>InputState.</returns>
|
|
public override InputState CreateActiveInputState(
|
|
IDiagramControl diagram,
|
|
IInputElement item,
|
|
IMouseButtonArgs mouseArgs,
|
|
IDiagramItem previouslyCreatedItem)
|
|
{
|
|
if (mouseArgs.ChangedButton == MouseButtonKind.Right)
|
|
{
|
|
return this.pointerTool.CreateActiveInputState(diagram, item, mouseArgs, previouslyCreatedItem);
|
|
}
|
|
|
|
return base.CreateActiveInputState(diagram, item, mouseArgs, previouslyCreatedItem);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default input state cursor.
|
|
/// </summary>
|
|
/// <param name="diagram">The diagram.</param>
|
|
/// <param name="item">The item.</param>
|
|
/// <param name="mouseArgs">The mouse arguments.</param>
|
|
/// <param name="previouslyCreatedItem">The previously created item.</param>
|
|
/// <returns>DiagramCursor.</returns>
|
|
public override DiagramCursor GetDefaultInputStateCursor(
|
|
IDiagramControl diagram,
|
|
IInputElement item,
|
|
IInputArgs mouseArgs,
|
|
IDiagramItem previouslyCreatedItem)
|
|
{
|
|
return this.pointerTool.GetDefaultInputStateCursor(diagram, item, mouseArgs, previouslyCreatedItem);
|
|
}
|
|
|
|
private static IDiagramConnector CreateConnector(IDiagramControl diagram)
|
|
{
|
|
CustomDiagramConnector connector = new CustomDiagramConnector() { Type = ConnectorType.Straight };
|
|
|
|
return connector;
|
|
}
|
|
}
|
|
} |