From 5e5da021ab4ccbb04bd63de1355c7f7fd0c62068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=89=BE=E7=AB=B9?= Date: Sat, 25 Mar 2023 22:10:49 +0800 Subject: [PATCH] =?UTF-8?q?mind=E7=9A=84=E6=8B=B7=E8=B4=9D=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/PageViewModel.cs | 2 + .../Serializables/SerializableObject.cs | 5 +- .../BaseViewModel/ConnectionViewModel.cs | 37 ++++++- .../Connector/FullyCreatedConnectorInfo.cs | 5 + .../BaseViewModel/DiagramViewModel.cs | 27 ++--- AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs | 14 ++- AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs | 19 ++-- AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs | 11 +- AIStudio.Wpf.Mind/Helpers/MindLayout.cs | 24 ++--- AIStudio.Wpf.Mind/Helpers/MindThemeHelper.cs | 6 ++ .../Helpers/OrganizationalLayout.cs | 15 +-- .../ViewModels/MindDiagramViewModel.cs | 27 +++-- AIStudio.Wpf.Mind/ViewModels/MindNode.cs | 100 ++++++++++++------ 13 files changed, 189 insertions(+), 103 deletions(-) diff --git a/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs b/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs index 327da44..2b60c6b 100644 --- a/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs +++ b/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs @@ -276,6 +276,7 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels FullyCreatedConnectorInfo sinkConnectorInfo = sinkItem.GetFullConnectorInfo(connectionItem.Id, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint, connectionItem.SinkInnerPoint); ConnectionViewModel connectionVM = new ConnectionViewModel(viewModel, sourceConnectorInfo, sinkConnectorInfo, connectionItem); + connectionVM.Id = Guid.NewGuid(); viewModel.Items.Add(connectionVM); } @@ -476,6 +477,7 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels FullyCreatedConnectorInfo sinkConnectorInfo = sinkItem.GetFullConnectorInfo(connectionItem.Id, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint, connectionItem.SinkIsPortless); ConnectionViewModel connectionVM = new ConnectionViewModel(viewModel, sourceConnectorInfo, sinkConnectorInfo, connectionItem); + connectionVM.Id = Guid.NewGuid(); viewModel.Items.Add(connectionVM); } diff --git a/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SerializableObject.cs b/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SerializableObject.cs index 781f963..330e943 100644 --- a/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SerializableObject.cs +++ b/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SerializableObject.cs @@ -66,8 +66,8 @@ namespace AIStudio.Wpf.DiagramDesigner.Models Type itemtype = TypeHelper.GetType(connection.SerializableTypeName); var connectionItem = SerializeHelper.DeserializeObject(itemtype, connection.SerializableString, ".json") as ConnectionItem; - connectionItem.SourceType = System.Type.GetType(connectionItem.SourceTypeName); - connectionItem.SinkType = System.Type.GetType(connectionItem.SinkTypeName); + connectionItem.SourceType = TypeHelper.GetType(connectionItem.SourceTypeName); + connectionItem.SinkType = TypeHelper.GetType(connectionItem.SinkTypeName); DesignerItemViewModelBase sourceItem = DiagramViewModelHelper.GetConnectorDataItem(items, connectionItem.SourceId, connectionItem.SourceType); if (sourceItem == null) continue; @@ -81,6 +81,7 @@ namespace AIStudio.Wpf.DiagramDesigner.Models FullyCreatedConnectorInfo sinkConnectorInfo = sinkItem.GetFullConnectorInfo(connectionItem.Id, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint, connectionItem.SinkInnerPoint); ConnectionViewModel connectionVM = new ConnectionViewModel(null, sourceConnectorInfo, sinkConnectorInfo, connectionItem); + connectionVM.Id = Guid.NewGuid(); connects.Add(connectionVM); } diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs index cc2f1f9..ded63d8 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs @@ -63,10 +63,10 @@ namespace AIStudio.Wpf.DiagramDesigner this.ShapeViewModel.PropertyChanged += ConnectorViewModel_PropertyChanged; this.PropertyChanged += ConnectorViewModel_PropertyChanged; - var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode); + var routetype = TypeHelper.GetType(RouterMode); Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal(); - var pathGeneratortype = GlobalType.AllTypes.Where(p => typeof(IPathGenerator).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == PathMode); + var pathGeneratortype = TypeHelper.GetType(PathMode); PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new ConnectingLineSmooth(); this.SourceConnectorInfo = sourceConnectorInfo; @@ -497,12 +497,12 @@ namespace AIStudio.Wpf.DiagramDesigner } break; case nameof(RouterMode): - var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode); + var routetype = TypeHelper.GetType(RouterMode); Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal(); UpdatePathGeneratorResult(); break; case nameof(PathMode): - var pathGeneratortype = GlobalType.AllTypes.Where(p => typeof(IPathGenerator).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == PathMode); + var pathGeneratortype = TypeHelper.GetType(PathMode); PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new ConnectingLineSmooth(); UpdatePathGeneratorResult(); break; @@ -729,6 +729,35 @@ namespace AIStudio.Wpf.DiagramDesigner SinkConnectorInfo = sink; } + public void SetPathGeneratorParameter(double smoothMargin, double smoothAutoSlope, double orthogonalShapeMargin, double orthogonalGlobalBoundsMargin) + { + bool hasChanged = false; + if (SmoothMargin != smoothMargin) + { + hasChanged = true; + SmoothMargin = smoothMargin; + } + if (SmoothAutoSlope != smoothAutoSlope) + { + hasChanged = true; + SmoothAutoSlope = smoothAutoSlope; + } + if (OrthogonalShapeMargin != orthogonalShapeMargin) + { + hasChanged = true; + OrthogonalShapeMargin = orthogonalShapeMargin; + } + if (OrthogonalGlobalBoundsMargin != orthogonalGlobalBoundsMargin) + { + hasChanged = true; + OrthogonalGlobalBoundsMargin = orthogonalGlobalBoundsMargin; + } + if (hasChanged) + { + UpdatePathGeneratorResult(); + } + } + public void SetVisible(bool visible) { Visible = visible; diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs index 6705a6d..d48facb 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs @@ -318,6 +318,11 @@ namespace AIStudio.Wpf.DiagramDesigner public virtual bool CanAttachTo(FullyCreatedConnectorInfo port) => port != this && !port.IsReadOnly && DataItem != port.DataItem; + + public override string ToString() + { + return $"({GetXRatioFromConnector()},{GetYRatioFromConnector()})"; + } } diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs index 40c4f04..ca5fba1 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs @@ -634,8 +634,8 @@ namespace AIStudio.Wpf.DiagramDesigner public event DiagramEventHandler Event; - private double OffsetX = 10; - private double OffsetY = 10; + protected double OffsetX = 10; + protected double OffsetY = 10; #endregion #region 命令 @@ -1508,8 +1508,8 @@ namespace AIStudio.Wpf.DiagramDesigner Connections = selectedConnections.Select(p => p.ToSerializableItem(".json")).Where(p => p != null).ToList(), }.ToJson(); - OffsetX = 10; - OffsetY = 10; + OffsetX = 0; + OffsetY = 0; System.Windows.Clipboard.Clear(); System.Windows.Clipboard.SetData(System.Windows.DataFormats.Serializable, json); @@ -1531,6 +1531,9 @@ namespace AIStudio.Wpf.DiagramDesigner return false; try { + OffsetX += 10; + OffsetY += 10; + List items = new List(); SerializableObject copyitem = JsonConvert.DeserializeObject(clipboardData); @@ -1555,10 +1558,7 @@ namespace AIStudio.Wpf.DiagramDesigner { items.Add(newItem); } - } - - OffsetX += 10; - OffsetY += 10; + } List connectors = new List(); foreach (var connection in copyitem.Connections) @@ -1570,8 +1570,8 @@ namespace AIStudio.Wpf.DiagramDesigner connectionItem.SourceId = mappingOldToNewIDs[connectionItem.SourceId]; connectionItem.SinkId = mappingOldToNewIDs[connectionItem.SinkId]; - connectionItem.SourceType = System.Type.GetType(connectionItem.SourceTypeName); - connectionItem.SinkType = System.Type.GetType(connectionItem.SinkTypeName); + connectionItem.SourceType = TypeHelper.GetType(connectionItem.SourceTypeName); + connectionItem.SinkType = TypeHelper.GetType(connectionItem.SinkTypeName); DesignerItemViewModelBase sourceItem = DiagramViewModelHelper.GetConnectorDataItem(items, connectionItem.SourceId, connectionItem.SourceType); ConnectorOrientation sourceConnectorOrientation = connectionItem.SourceOrientation; FullyCreatedConnectorInfo sourceConnectorInfo = sourceItem.GetFullConnectorInfo(connectionItem.Id, sourceConnectorOrientation, connectionItem.SourceXRatio, connectionItem.SourceYRatio, connectionItem.SourceInnerPoint, connectionItem.SourceIsPortless); @@ -1581,6 +1581,7 @@ namespace AIStudio.Wpf.DiagramDesigner FullyCreatedConnectorInfo sinkConnectorInfo = sinkItem.GetFullConnectorInfo(connectionItem.Id, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint, connectionItem.SinkIsPortless); ConnectionViewModel connectionVM = new ConnectionViewModel(this, sourceConnectorInfo, sinkConnectorInfo, connectionItem); + connectionVM.Id = Guid.NewGuid(); connectors.Add(connectionVM); } @@ -1634,8 +1635,7 @@ namespace AIStudio.Wpf.DiagramDesigner { if (Paste(null) == false) return false; - OffsetX = 0; - OffsetY = 0; + if (Delete(null) == false) return false; @@ -2102,6 +2102,7 @@ namespace AIStudio.Wpf.DiagramDesigner } }); } + private void ExecuteSendToBackCommand(object parameter) { List selectionSorted; @@ -2151,6 +2152,7 @@ namespace AIStudio.Wpf.DiagramDesigner } }); } + private void ExecuteDistributeHorizontalCommand(object parameter) { IEnumerable selectedItems; @@ -2214,6 +2216,7 @@ namespace AIStudio.Wpf.DiagramDesigner }); } } + private void ExecuteDistributeVerticalCommand(object parameter) { IEnumerable selectedItems; diff --git a/AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs b/AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs index b81b6ca..25e3c9b 100644 --- a/AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs +++ b/AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs @@ -88,14 +88,10 @@ namespace AIStudio.Wpf.Mind.Helpers { connector?.UpdateConnectionMode(source.FirstConnector, sink.FirstConnector, DrawMode.ConnectingLineStraight.ToString(), RouterMode.RouterOrthogonal.ToString()); } - connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; - connector.SmoothMargin = 20; - connector.SmoothAutoSlope = 0.2; - connector.OrthogonalShapeMargin = 2; - connector.OrthogonalGlobalBoundsMargin = 5; + connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle; connector.ShapeViewModel.SinkMarker.SizeStyle = source.ShapeViewModel.SinkMarker.SizeStyle; - + connector.SetPathGeneratorParameter(smoothMargin: 20, smoothAutoSlope: 0.2, orthogonalShapeMargin: 2, orthogonalGlobalBoundsMargin: 5); return connector; } @@ -147,7 +143,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.DesiredSize.Width / 2 - child.ItemWidth / 2 + child.Offset.X; child.Top = top + child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left + child.DesiredSize.Width / 2 - child.ItemWidth / 2, top + child.Spacing.Height); left += child.DesiredSize.Width; ArrangeOverride(child); @@ -158,6 +154,8 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.SetVisible(child.Visible); } } + + mindNode.DesiredPosition = mindNode.Position; } else { @@ -169,7 +167,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.Offset.X; child.Top = top + child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left, top + child.Spacing.Height); top += child.DesiredSize.Height; ArrangeOverride(child); diff --git a/AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs b/AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs index 7cc2226..93309f4 100644 --- a/AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs +++ b/AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs @@ -115,12 +115,9 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.UpdateConnectionMode(source.FirstConnector, sink.FirstConnector, drawMode.ToString(), routerMode.ToString()); } connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; - connector.SmoothMargin = 20; - connector.SmoothAutoSlope = 0.2; - connector.OrthogonalShapeMargin = 2; - connector.OrthogonalGlobalBoundsMargin = 5; connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle; connector.ShapeViewModel.SinkMarker.SizeStyle = source.ShapeViewModel.SinkMarker.SizeStyle; + connector.SetPathGeneratorParameter(smoothMargin: 20, smoothAutoSlope: 0.2, orthogonalShapeMargin: 2, orthogonalGlobalBoundsMargin: 5); return connector; } @@ -186,7 +183,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = topleft + child.Spacing.Width + child.Offset.X; child.Top = toptop - child.ItemHeight - child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(topleft + child.Spacing.Width, toptop - child.ItemHeight - child.Spacing.Height); topleft += child.DesiredSize.Width; ArrangeOverride(child); @@ -209,7 +206,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = bottomleft + child.Spacing.Width + child.Offset.X; child.Top = bottomtop + child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(bottomleft + child.Spacing.Width, bottomtop + child.Spacing.Height); bottomleft += child.DesiredSize.Width; ArrangeOverride(child); @@ -220,6 +217,8 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.SetVisible(child.Visible); } } + + mindNode.DesiredPosition = mindNode.Position; } else if (mindNode.NodeLevel == 1) { @@ -234,7 +233,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = x0 + (h + child.DesiredSize.Height - child.ItemHeight / 2 - child.Spacing.Height) + child.Offset.X; child.Top = y0 - (h + child.DesiredSize.Height - child.Spacing.Height) + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(x0 + (h + child.DesiredSize.Height - child.ItemHeight / 2 - child.Spacing.Height), y0 - (h + child.DesiredSize.Height - child.Spacing.Height)); h += child.DesiredSize.Height; ArrangeOverride(child); @@ -257,7 +256,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = x0 + (h + child.DesiredSize.Height - child.ItemHeight / 2 - child.Spacing.Height) + child.Offset.X; child.Top = y0 + (h + child.DesiredSize.Height - child.ItemHeight - child.Spacing.Height) + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(x0 + (h + child.DesiredSize.Height - child.ItemHeight / 2 - child.Spacing.Height), y0 + (h + child.DesiredSize.Height - child.ItemHeight - child.Spacing.Height)); h += child.DesiredSize.Height; ArrangeOverride(child); @@ -282,7 +281,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.Offset.X; child.Top = top + child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left, top + child.Spacing.Height); top += child.DesiredSize.Height; ArrangeOverride(child); @@ -304,7 +303,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.Offset.X; child.Top = bottom - child.Spacing.Height - child.ItemHeight + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left, bottom - child.Spacing.Height - child.ItemHeight); bottom -= child.DesiredSize.Height; ArrangeOverride(child); diff --git a/AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs b/AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs index 3ed77e4..666733d 100644 --- a/AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs +++ b/AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs @@ -86,13 +86,10 @@ namespace AIStudio.Wpf.Mind.Helpers { connector?.UpdateConnectionMode(source.FirstConnector, sink.FirstConnector, DrawMode.ConnectingLineSmooth.ToString(), RouterMode.RouterNormal.ToString()); } - connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; - connector.SmoothMargin = 20; - connector.SmoothAutoSlope = 0.2; - connector.OrthogonalShapeMargin = 2; - connector.OrthogonalGlobalBoundsMargin = 5; + connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle; connector.ShapeViewModel.SinkMarker.SizeStyle = source.ShapeViewModel.SinkMarker.SizeStyle; + connector.SetPathGeneratorParameter(smoothMargin: 20, smoothAutoSlope: 0.2, orthogonalShapeMargin: 2, orthogonalGlobalBoundsMargin: 5); return connector; } @@ -134,7 +131,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.Spacing.Width + child.Offset.X; child.Top = top + child.DesiredSize.Height / 2 - child.ItemHeight / 2 + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left + child.Spacing.Width, top + child.DesiredSize.Height / 2 - child.ItemHeight / 2); top += child.DesiredSize.Height; ArrangeOverride(child); @@ -144,6 +141,8 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.SetSinkPort(child.LeftConnector); connector?.SetVisible(child.Visible); } + + mindNode.DesiredPosition = mindNode.Position; } } diff --git a/AIStudio.Wpf.Mind/Helpers/MindLayout.cs b/AIStudio.Wpf.Mind/Helpers/MindLayout.cs index 613aaee..0771e3f 100644 --- a/AIStudio.Wpf.Mind/Helpers/MindLayout.cs +++ b/AIStudio.Wpf.Mind/Helpers/MindLayout.cs @@ -30,7 +30,7 @@ namespace AIStudio.Wpf.Mind.Helpers mindNode.ClearConnectors(); var port = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.None, true) { XRatio = 0.5, YRatio = 0.5 }; - mindNode.AddConnector(port); + mindNode.AddConnector(port); } mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle; mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall; @@ -89,12 +89,9 @@ namespace AIStudio.Wpf.Mind.Helpers } connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; - connector.SmoothMargin = 20; - connector.SmoothAutoSlope = 0.2; - connector.OrthogonalShapeMargin = 2; - connector.OrthogonalGlobalBoundsMargin = 5; connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle; connector.ShapeViewModel.SinkMarker.SizeStyle = source.ShapeViewModel.SinkMarker.SizeStyle; + connector.SetPathGeneratorParameter(smoothMargin: 20, smoothAutoSlope: 0.2, orthogonalShapeMargin: 2, orthogonalGlobalBoundsMargin: 5); return connector; } @@ -114,7 +111,7 @@ namespace AIStudio.Wpf.Mind.Helpers public SizeBase MeasureOverride(MindNode mindNode, bool isExpanded = true) { - var sizewithSpacing = mindNode.SizeWithSpacing; + var sizewithSpacing = mindNode.SizeWithSpacing; if (mindNode.Children?.Count > 0) { if (mindNode.NodeLevel == 0) @@ -132,7 +129,7 @@ namespace AIStudio.Wpf.Mind.Helpers var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray(); sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.MaxOrDefault(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.SumOrDefault(p => p.Height))); } - } + } mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0); mindNode.Visible = isExpanded; @@ -145,14 +142,14 @@ namespace AIStudio.Wpf.Mind.Helpers { if (mindNode.Children?.Count > 0) { - var rights = mindNode.Children.Where(p => p.ConnectorOrientation == ConnectorOrientation.Left).ToList(); + var rights = mindNode.Children.Where(p => p.ConnectorOrientation == ConnectorOrientation.Left).ToList(); double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width; double lefttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, rights.SumOrDefault(p => p.DesiredSize.Height)) / 2; foreach (var child in rights) { child.Left = left + child.Spacing.Width + child.Offset.X; child.Top = lefttop + child.DesiredSize.Height / 2 - child.ItemHeight / 2 + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left + child.Spacing.Width, lefttop + child.DesiredSize.Height / 2 - child.ItemHeight / 2); lefttop += child.DesiredSize.Height; ArrangeOverride(child); @@ -170,7 +167,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = right - child.Spacing.Width - child.ItemWidth + child.Offset.X; child.Top = righttop + child.DesiredSize.Height / 2 - child.ItemHeight / 2 + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(right - child.Spacing.Width - child.ItemWidth, righttop + child.DesiredSize.Height / 2 - child.ItemHeight / 2); righttop += child.DesiredSize.Height; ArrangeOverride(child); @@ -181,6 +178,8 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.SetVisible(child.Visible); } } + + mindNode.DesiredPosition = mindNode.Position; } else { @@ -194,7 +193,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.Spacing.Width + child.Offset.X; child.Top = top + child.DesiredSize.Height / 2 - child.ItemHeight / 2 + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left + child.Spacing.Width, top + child.DesiredSize.Height / 2 - child.ItemHeight / 2); top += child.DesiredSize.Height; ArrangeOverride(child); @@ -216,7 +215,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = right - child.Spacing.Width - child.ItemWidth + child.Offset.X; child.Top = top + child.DesiredSize.Height / 2 - child.ItemHeight / 2 + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(right - child.Spacing.Width - child.ItemWidth, top + child.DesiredSize.Height / 2 - child.ItemHeight / 2); top += child.DesiredSize.Height; ArrangeOverride(child); @@ -230,6 +229,7 @@ namespace AIStudio.Wpf.Mind.Helpers } } + } diff --git a/AIStudio.Wpf.Mind/Helpers/MindThemeHelper.cs b/AIStudio.Wpf.Mind/Helpers/MindThemeHelper.cs index ef4bccf..a647d66 100644 --- a/AIStudio.Wpf.Mind/Helpers/MindThemeHelper.cs +++ b/AIStudio.Wpf.Mind/Helpers/MindThemeHelper.cs @@ -496,6 +496,7 @@ namespace AIStudio.Wpf.Mind.Helpers { Name = "冷光黄", Key = "CoolLightYellow", + Dark = true, MindThemeLevel1 = new MindTheme() { ItemWidth = 110, @@ -534,6 +535,7 @@ namespace AIStudio.Wpf.Mind.Helpers { Name = "紧凑黄", Key = "CoolLightYellowMini", + Dark = true, MindThemeLevel1 = new MindTheme() { ItemWidth = 110, @@ -650,6 +652,10 @@ namespace AIStudio.Wpf.Mind.Helpers { get; set; } + public bool Dark + { + get; set; + } public MindTheme MindThemeLevel1 { get; set; diff --git a/AIStudio.Wpf.Mind/Helpers/OrganizationalLayout.cs b/AIStudio.Wpf.Mind/Helpers/OrganizationalLayout.cs index da58b78..5e007a1 100644 --- a/AIStudio.Wpf.Mind/Helpers/OrganizationalLayout.cs +++ b/AIStudio.Wpf.Mind/Helpers/OrganizationalLayout.cs @@ -88,13 +88,10 @@ namespace AIStudio.Wpf.Mind.Helpers { connector?.UpdateConnectionMode(source.FirstConnector, sink.FirstConnector, DrawMode.ConnectingLineStraight.ToString(), RouterMode.RouterOrthogonal.ToString()); } - connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; - connector.SmoothMargin = 20; - connector.SmoothAutoSlope = 0.2; - connector.OrthogonalShapeMargin = 2; - connector.OrthogonalGlobalBoundsMargin = 5; + connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor; connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle; connector.ShapeViewModel.SinkMarker.SizeStyle = sink.ShapeViewModel.SinkMarker.SizeStyle; + connector.SetPathGeneratorParameter(smoothMargin: 20, smoothAutoSlope: 0.2, orthogonalShapeMargin: 2, orthogonalGlobalBoundsMargin: 5); return connector; } @@ -136,7 +133,7 @@ namespace AIStudio.Wpf.Mind.Helpers { child.Left = left + child.DesiredSize.Width / 2 - child.ItemWidth / 2 + child.Offset.X; child.Top = top + child.Spacing.Height + child.Offset.Y; - child.DesiredPosition = child.Position; + child.DesiredPosition = new PointBase(left + child.DesiredSize.Width / 2 - child.ItemWidth / 2, top + child.Spacing.Height); left += child.DesiredSize.Width; ArrangeOverride(child); @@ -146,6 +143,12 @@ namespace AIStudio.Wpf.Mind.Helpers connector?.SetSinkPort(child.TopConnector); connector?.SetVisible(child.Visible); } + + } + + if (mindNode.NodeLevel == 0) + { + mindNode.DesiredPosition = mindNode.Position; } } diff --git a/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs index 29433b8..9501a42 100644 --- a/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs +++ b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Windows.Input; using System.Windows.Media; using AIStudio.Wpf.DiagramDesigner; +using AIStudio.Wpf.DiagramDesigner.Geometrys; using AIStudio.Wpf.Mind.Helpers; namespace AIStudio.Wpf.Mind.ViewModels @@ -426,7 +427,7 @@ namespace AIStudio.Wpf.Mind.ViewModels if (items?.Count == 0) { - var node = new MindNode(this) { Text = $"分支主题{parent.Children.Count + 1}"}; + var node = new MindNode(this) { Text = $"分支主题{parent.Children.Count + 1}" }; items.Add(node); } @@ -463,7 +464,7 @@ namespace AIStudio.Wpf.Mind.ViewModels else { node = SelectedItem as MindNode; - } + } if (node.Parent is MindNode parent) { @@ -616,6 +617,7 @@ namespace AIStudio.Wpf.Mind.ViewModels protected override bool Delete(object parameter) { List nodes = new List(); + List others = new List(); if (parameter is MindNode node1) { nodes.Add(node1); @@ -627,6 +629,8 @@ namespace AIStudio.Wpf.Mind.ViewModels else { nodes.AddRange(SelectedItems.OfType()); + + others = SelectedItems.Where(p => !(p is MindNode)).ToList(); } if (nodes.FirstOrDefault()?.IsEditing != false) @@ -641,16 +645,14 @@ namespace AIStudio.Wpf.Mind.ViewModels () => { foreach (var node in nodes) { - if (node.NodeLevel == 0) - { - DirectRemoveItemCommand.Execute(node); - } - else - { - node.ParentNode?.RemoveChild(node, true); - } + node.Remove(true); } RootItems.ForEach(p => p.LayoutUpdated()); + + if (others.Any()) + { + base.Delete(others); + } }, () => { foreach (var node in nodes) @@ -669,9 +671,11 @@ namespace AIStudio.Wpf.Mind.ViewModels #region 复制,粘贴 protected override void FixOtherInfo(List items) { + List parents = new List(); foreach (var item in items.OfType()) { + //item.DesiredPosition = new PointBase(item.DesiredPosition?.X ?? 0 + OffsetX, item.DesiredPosition?.Y ?? 0 + OffsetY); var parent = Items.OfType().FirstOrDefault(p => p.Id == item.ParentId); if (parent != null && !items.Contains(parent)) { @@ -679,6 +683,7 @@ namespace AIStudio.Wpf.Mind.ViewModels } else if (item.ParentId == Guid.Empty) { + item.Offset = new PointBase(OffsetX, OffsetX); parents.Add(item); item.InitLayout(false); } @@ -806,7 +811,7 @@ namespace AIStudio.Wpf.Mind.ViewModels if (obj is string mindThemeModel) { MindThemeModel = MindThemeHelper.GetTheme(mindThemeModel); - if (mindThemeModel.StartsWith("CoolLightYellow")) + if (MindThemeModel?.Dark == true) { PageBackground = Colors.Black; } diff --git a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs index dfee264..a8321d9 100644 --- a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs +++ b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs @@ -98,13 +98,12 @@ namespace AIStudio.Wpf.Mind.ViewModels public void InitLayout(bool initAppearance) { - var layout = GlobalType.AllTypes.Where(p => typeof(IMindLayout).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == MindType.ToString() + "Layout"); + var layout = TypeHelper.GetType(MindType.ToString() + "Layout"); MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout(); - IsInnerConnector = true; - MindLayout.Appearance(this, MindThemeModel, initAppearance); - this.PropertyChanged -= this.Item_PropertyChanged; + IsInnerConnector = true; + MindLayout.Appearance(this, MindThemeModel, initAppearance); this.PropertyChanged += this.Item_PropertyChanged; } @@ -231,14 +230,51 @@ namespace AIStudio.Wpf.Mind.ViewModels get; set; } - public PointBase DesiredPosition + public PointBase? DesiredPosition { get; set; } public PointBase Offset { - get; set; + get + { + PointBase point; + if (NodeLevel == 0) + { + if (DesiredPosition == null) + { + point = new PointBase(); + } + else + { + point = new PointBase(Position.X - DesiredPosition.Value.X, Position.Y - DesiredPosition.Value.Y); + } + } + else + { + if (DesiredPosition == null) + { + point = new PointBase(); + } + else + { + point = new PointBase(Position.X - DesiredPosition.Value.X - RootNode.Offset.X, Position.Y - DesiredPosition.Value.Y - RootNode.Offset.Y); + } + } + return point; + } + set + { + if (NodeLevel == 0) + { + DesiredPosition = new PointBase(Position.X - value.X, Position.Y - value.Y); + } + else + { + DesiredPosition = new PointBase(Position.X - value.X - RootNode.Offset.X, Position.Y - value.Y - RootNode.Offset.Y); + } + } } private ConnectorOrientation _connectorOrientation = ConnectorOrientation.Left; @@ -494,7 +530,31 @@ namespace AIStudio.Wpf.Mind.ViewModels { foreach (var child in item.Children.ToList()) { - item.RemoveChild(child); + item.RemoveChild(child, removeall); + } + } + } + } + + public void Remove(bool removeall = false) + { + this.PropertyChanged -= Item_PropertyChanged; + if (this.ParentNode != null) + { + this.ParentNode.Children.Remove(this); + } + var connectors = Root?.Items.OfType().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList(); + + Root?.DirectRemoveItemCommand.Execute(this); + Root?.DirectRemoveItemCommand.Execute(connectors); + + if (removeall) + { + if (this.Children?.Count > 0) + { + foreach (var child in this.Children.ToList()) + { + child.Remove(removeall); } } } @@ -519,9 +579,7 @@ namespace AIStudio.Wpf.Mind.ViewModels private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (GetLevel1Node()?.LayoutUpdating == true) return; - - if (Root == null) return; + if (GetLevel1Node()?.LayoutUpdating == true) return; switch (e.PropertyName) { @@ -535,28 +593,6 @@ namespace AIStudio.Wpf.Mind.ViewModels case nameof(NodeLevel): MindLayout?.Appearance(this); break; - case nameof(Left): - { - if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs) - { - if (NodeLevel > 0 && IsSelected) - { - UpdateOffsetX((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue); - } - } - break; - } - case nameof(Top): - { - if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs) - { - if (NodeLevel > 0 && IsSelected) - { - UpdateOffsetY((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue); - } - } - break; - } case nameof(Text): { ItemWidth = Math.Max(ItemWidth, GetTextDisplayWidthHelper.GetTextDisplayWidth(Text, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, FontViewModel.FontSize) + 30);