结构调整

This commit is contained in:
kwai
2023-02-21 19:47:46 +08:00
parent 71ed33f881
commit c227076076
7 changed files with 594 additions and 386 deletions

View File

@@ -11,6 +11,7 @@ using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.Mind.ViewModels;
using AIStudio.Wpf.Mind;
namespace AIStudio.Wpf.Flowchart
{
@@ -35,30 +36,44 @@ namespace AIStudio.Wpf.Flowchart
DiagramViewModel.AllowDrop = false;
}
private MindType _mindType = Mind.MindType.Directory;
public MindType MindType
{
get
{
return _mindType;
}
set
{
SetProperty(ref _mindType, value);
}
}
protected override void Init()
{
base.Init();
MindNode level1node = new MindNode(DiagramViewModel, Mind.NodeLevel.Level1) { Text = "思维导图" };
MindNode level1node = new MindNode(DiagramViewModel, Mind.NodeLevel.Level1, MindType) { Text = "思维导图" };
DiagramViewModel.DirectAddItemCommand.Execute(level1node);
DiagramViewModel.CenterMoveCommand.Execute(level1node);
MindNode level2node1_1 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2) { Text = "分支主题1" };
MindNode level2node1_1 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2, MindType) { Text = "分支主题1" };
level1node.AddChild(level2node1_1);
MindNode level3node1_1_1 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3) { Text = "分支主题1_1" };
MindNode level3node1_1_1 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3, MindType) { Text = "分支主题1_1" };
level2node1_1.AddChild(level3node1_1_1);
MindNode level3node1_1_2 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3) { Text = "分支主题1_2" };
MindNode level3node1_1_2 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3, MindType) { Text = "分支主题1_2" };
level2node1_1.AddChild(level3node1_1_2);
MindNode level3node1_1_3 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3) { Text = "分支主题1_3" };
MindNode level3node1_1_3 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level3, MindType) { Text = "分支主题1_3" };
level2node1_1.AddChild(level3node1_1_3);
MindNode level2node1_2 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2) { Text = "分支主题2" };
MindNode level2node1_2 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2, MindType) { Text = "分支主题2" };
level1node.AddChild(level2node1_2);
MindNode level2node1_3 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2) { Text = "分支主题3" };
MindNode level2node1_3 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2, MindType) { Text = "分支主题3" };
level1node.AddChild(level2node1_3);
DiagramViewModel.ClearSelectedItemsCommand.Execute(null);

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.Mind.ViewModels;
namespace AIStudio.Wpf.Mind.Helpers
{
public class DirectoryLayout : IMindLayout
{
public void Appearance(MindNode mindNode)
{
switch (mindNode.NodeLevel)
{
case NodeLevel.Level1:
{
mindNode.ItemWidth = 110;
mindNode.ItemHeight = 40;
mindNode.ClearConnectors();
var port = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.5, YRatio = 1 };
mindNode.AddConnector(port);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.FillColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.FontViewModel.FontColor = Colors.White;
mindNode.FontViewModel.FontSize = 15;
mindNode.Spacing = new SizeBase(50, 15);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level2:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Top, true) { XRatio = 0.5, YRatio = 0 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level3:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
mindNode.CornerRadius = new System.Windows.CornerRadius(0);
mindNode.BorderThickness = new System.Windows.Thickness(0, 0, 0, 0);
break;
}
}
}
public void LayoutUpdated(MindNode mindNode)
{
if (mindNode == null) return;
mindNode.LayoutUpdating = true;
var size = MeasureOverride(mindNode);
ArrangeOverride(mindNode);
mindNode.Root.BringToFrontCommand.Execute(new SelectableDesignerItemViewModelBase[] { mindNode });
mindNode.Root?.ReconnectLinksToClosestPorts();
mindNode.LayoutUpdating = false;
}
public SizeBase MeasureOverride(MindNode mindNode, bool isExpanded = true)
{
var sizewithSpacing = mindNode.SizeWithSpacing;
if (mindNode.Children?.Count > 0)
{
if (mindNode.NodeLevel == NodeLevel.Level1)
{
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.Sum(p => p.Width)), sizewithSpacing.Height + childrensizes.Max(p => p.Height));
}
else
{
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width * 0.5 + childrensizes.Max(p => p.Width), sizewithSpacing.Height + childrensizes.Sum(p => p.Height));
}
}
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
mindNode.Visible = isExpanded;
var connectors = mindNode.Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == mindNode).ToList();
connectors?.ForEach(p => p.Visible = mindNode.Visible);
return mindNode.DesiredSize;
}
public void ArrangeOverride(MindNode mindNode)
{
if (mindNode.NodeLevel == NodeLevel.Level1)
{
double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.Sum(p => p.DesiredSize.Width)) / 2;
double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
if (mindNode.Children?.Count > 0)
{
foreach (var child in mindNode.Children)
{
child.Left = left + child.Spacing.Width + child.Offset.X;
child.Top = top + child.Spacing.Height + child.Offset.Y;
child.DesiredPosition = child.Position;
left += child.DesiredSize.Width;
ArrangeOverride(child);
}
}
}
else
{
double left = mindNode.MiddlePosition.X;
double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
if (mindNode.Children?.Count > 0)
{
foreach (var child in mindNode.Children)
{
child.Left = left + child.Offset.X;
child.Top = top + child.Spacing.Height + child.Offset.Y;
child.DesiredPosition = child.Position;
top += child.DesiredSize.Height;
ArrangeOverride(child);
}
}
}
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using AIStudio.Wpf.Mind.ViewModels;
namespace AIStudio.Wpf.Mind.Helpers
{
public interface IMindLayout
{
void Appearance(MindNode mindNode);
void LayoutUpdated(MindNode mindNode);
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.Mind.ViewModels;
namespace AIStudio.Wpf.Mind.Helpers
{
public class LogicalLayout : IMindLayout
{
public void Appearance(MindNode mindNode)
{
switch (mindNode.NodeLevel)
{
case NodeLevel.Level1:
{
mindNode.ItemWidth = 110;
mindNode.ItemHeight = 40;
mindNode.ClearConnectors();
var port = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.None, true) { XRatio = 0.5, YRatio = 0.5 };
mindNode.AddConnector(port);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.FillColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.FontViewModel.FontColor = Colors.White;
mindNode.FontViewModel.FontSize = 15;
mindNode.Spacing = new SizeBase(50, 15);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level2:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 0.5 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level3:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 1 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 1 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
mindNode.CornerRadius = new System.Windows.CornerRadius(0);
mindNode.BorderThickness = new System.Windows.Thickness(0, 0, 0, 1);
break;
}
}
}
public void LayoutUpdated(MindNode mindNode)
{
if (mindNode == null) return;
mindNode.LayoutUpdating = true;
var size = MeasureOverride(mindNode);
ArrangeOverride(mindNode);
mindNode.Root.BringToFrontCommand.Execute(new SelectableDesignerItemViewModelBase[] { mindNode });
mindNode.Root?.ReconnectLinksToClosestPorts();
mindNode.LayoutUpdating = false;
}
public SizeBase MeasureOverride(MindNode mindNode, bool isExpanded = true)
{
var sizewithSpacing = mindNode.SizeWithSpacing;
if (mindNode.Children?.Count > 0)
{
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
}
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
mindNode.Visible = isExpanded;
var connectors = mindNode.Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == mindNode).ToList();
connectors?.ForEach(p => p.Visible = mindNode.Visible);
return mindNode.DesiredSize;
}
public void ArrangeOverride(MindNode mindNode)
{
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
if (mindNode.Children?.Count > 0)
{
foreach (var child in mindNode.Children)
{
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;
top += child.DesiredSize.Height;
ArrangeOverride(child);
}
}
}
}
}

View File

@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.Mind.ViewModels;
namespace AIStudio.Wpf.Mind.Helpers
{
public class MindLayout : IMindLayout
{
public void Appearance(MindNode mindNode)
{
switch (mindNode.NodeLevel)
{
case NodeLevel.Level1:
{
mindNode.ItemWidth = 110;
mindNode.ItemHeight = 40;
mindNode.ClearConnectors();
var port = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.None, true) { XRatio = 0.5, YRatio = 0.5 };
mindNode.AddConnector(port);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.FillColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.FontViewModel.FontColor = Colors.White;
mindNode.FontViewModel.FontSize = 15;
mindNode.Spacing = new SizeBase(50, 15);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level2:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 0.5 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level3:
{
mindNode.ItemWidth = 80;
mindNode.ItemHeight = 25;
mindNode.ClearConnectors();
var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 1 };
mindNode.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 1 };
mindNode.AddConnector(port2);
mindNode.IsInnerConnector = true;
mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
mindNode.CornerRadius = new System.Windows.CornerRadius(0);
mindNode.BorderThickness = new System.Windows.Thickness(0, 0, 0, 1);
break;
}
}
}
public void LayoutUpdated(MindNode mindNode)
{
if (mindNode == null) return;
mindNode.LayoutUpdating = true;
var size = MeasureOverride(mindNode);
ArrangeOverride(mindNode);
mindNode.Root.BringToFrontCommand.Execute(new SelectableDesignerItemViewModelBase[] { mindNode });
mindNode.Root?.ReconnectLinksToClosestPorts();
mindNode.LayoutUpdating = false;
}
public SizeBase MeasureOverride(MindNode mindNode, bool isExpanded = true)
{
var sizewithSpacing = mindNode.SizeWithSpacing;
if (mindNode.Children?.Count > 0)
{
if (mindNode.NodeLevel == NodeLevel.Level1)
{
var rights = mindNode.Children.Where((p, index) => index % 2 == 0).ToList();
rights.ForEach(p => p.IsRightLayout = true);
var rightsizes = rights.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
var lefts = mindNode.Children.Where((p, index) => index % 2 == 1).ToList();
lefts.ForEach(p => p.IsRightLayout = false);
var leftsizes = lefts.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + rightsizes.Max(p => p.Width) + +leftsizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, Math.Max(rightsizes.Sum(p => p.Height), leftsizes.Sum(p => p.Height))));
}
else
{
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
}
}
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
mindNode.Visible = isExpanded;
var connectors = mindNode.Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == mindNode).ToList();
connectors?.ForEach(p => p.Visible = mindNode.Visible);
return mindNode.DesiredSize;
}
public void ArrangeOverride(MindNode mindNode)
{
if (mindNode.NodeLevel == NodeLevel.Level1)
{
if (mindNode.Children?.Count > 0)
{
var rights = mindNode.Children.Where(p => p.IsRightLayout == true).ToList();
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
double lefttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, rights.Sum(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;
lefttop += child.DesiredSize.Height;
ArrangeOverride(child);
}
var lefts = mindNode.Children.Where(p => p.IsRightLayout == false).ToList();
double right = mindNode.MiddlePosition.X - mindNode.ItemWidth / 2 - mindNode.Spacing.Width;
double righttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, lefts.Sum(p => p.DesiredSize.Height)) / 2;
foreach (var child in lefts)
{
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;
righttop += child.DesiredSize.Height;
ArrangeOverride(child);
}
}
}
else
{
if (mindNode.GetLevel2Node().IsRightLayout)
{
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
if (mindNode.Children?.Count > 0)
{
foreach (var child in mindNode.Children)
{
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;
top += child.DesiredSize.Height;
ArrangeOverride(child);
}
}
}
else
{
double right = mindNode.MiddlePosition.X - mindNode.ItemWidth / 2 - mindNode.Spacing.Width;
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
if (mindNode.Children?.Count > 0)
{
foreach (var child in mindNode.Children)
{
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;
top += child.DesiredSize.Height;
ArrangeOverride(child);
}
}
}
}
}
}
}

View File

@@ -6,6 +6,7 @@
<dd:ColorBrushConverter x:Key="ColorBrushConverter"/>
<dd:DoubleToCornerRadius x:Key="DoubleToCornerRadius"/>
<dd:IntToVisibilityConverter x:Key="IntToVisibilityConverter"/>
<dd:DoubleToThickness x:Key="DoubleToThickness"/>
<!-- Toggle Button -->
<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
@@ -54,10 +55,10 @@
</ContextMenu>
</Grid.ContextMenu>
<Grid IsHitTestVisible="False">
<Border BorderThickness="1"
<Border BorderThickness="{Binding BorderThickness}"
BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
CornerRadius="{Binding CornerRadius,Converter={StaticResource DoubleToCornerRadius}}">
CornerRadius="{Binding CornerRadius}">
</Border>
</Grid>
</Grid>
@@ -81,16 +82,15 @@
</ContextMenu>
</Grid.ContextMenu>
<Grid IsHitTestVisible="False">
<Border BorderThickness="1"
<Border BorderThickness="{Binding BorderThickness}"
BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
CornerRadius="{Binding CornerRadius,Converter={StaticResource DoubleToCornerRadius}}">
CornerRadius="{Binding CornerRadius}">
</Border>
</Grid>
<ToggleButton x:Name="toggle" IsChecked="{Binding IsExpanded}" Style="{StaticResource ExpandCollapseToggleStyle}" HorizontalAlignment="Left" Margin="-15,0,0,0" Visibility="{Binding Children.Count,Converter={StaticResource IntToVisibilityConverter}}"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsRightLayout}" Value="false">
<Setter TargetName="toggle" Property="HorizontalAlignment" Value="Right"/>
<Setter TargetName="toggle" Property="Margin" Value="0,0,-15,0"/>
@@ -116,10 +116,10 @@
</ContextMenu>
</Grid.ContextMenu>
<Grid IsHitTestVisible="False">
<Border BorderThickness="0,0,0,1"
<Border BorderThickness="{Binding BorderThickness}"
BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
CornerRadius="{Binding CornerRadius}">
</Border>
</Grid>
<ToggleButton x:Name="toggle" IsChecked="{Binding IsExpanded}" Style="{StaticResource ExpandCollapseToggleStyle}" HorizontalAlignment="Left" Margin="-15,0,0,0" Visibility="{Binding Children.Count,Converter={StaticResource IntToVisibilityConverter}}"/>

View File

@@ -5,33 +5,40 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Models;
using AIStudio.Wpf.Mind.Helpers;
namespace AIStudio.Wpf.Mind.ViewModels
{
public class MindNode : DesignerItemViewModelBase
{
public MindNode(NodeLevel nodeLevel) : this(null, nodeLevel)
public MindNode(NodeLevel nodeLevel, MindType mindType = MindType.Mind) : this(null, nodeLevel, mindType)
{
}
public MindNode(IDiagramViewModel root, NodeLevel nodeLevel) : base(root)
public MindNode(IDiagramViewModel root, NodeLevel nodeLevel, MindType mindType = MindType.Mind) : base(root)
{
NodeLevel = nodeLevel;
LevelInit(true);
MindType = mindType;
InitLayout();
MindLayout.Appearance(this);
}
public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
{
InitLayout();
}
public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
{
InitLayout();
}
protected override void Init(IDiagramViewModel root)
@@ -47,116 +54,17 @@ namespace AIStudio.Wpf.Mind.ViewModels
MoveForwardCommand = new SimpleCommand(Command_Enable, ExecuteMoveForwardCommand);
MoveBackCommand = new SimpleCommand(Command_Enable, ExecuteMoveBackCommand);
BuildMenuOptions();
this.PropertyChanged += this.Item_PropertyChanged;
}
private void LevelInit(bool init = false)
{
switch (NodeLevel)
{
case NodeLevel.Level1:
{
ItemWidth = 110;
ItemHeight = 40;
this.ClearConnectors();
switch (MindType)
{
case MindType.Mind:
case MindType.Logical:
{
var port = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.None, true) { XRatio = 0.5, YRatio = 0.5 };
this.AddConnector(port);
break;
}
case MindType.Directory:
{
var port = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Bottom, true) { XRatio = 0.5, YRatio = 1 };
this.AddConnector(port);
break;
}
}
IsInnerConnector = true;
ColorViewModel.FillColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
FontViewModel.FontColor = Colors.White;
FontViewModel.FontSize = 15;
Spacing = new SizeBase(50, 15);
ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle;
ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level2:
{
ItemWidth = 80;
ItemHeight = 25;
this.ClearConnectors();
switch (MindType)
{
case MindType.Mind:
case MindType.Logical:
{
var port1 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
this.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 0.5 };
this.AddConnector(port2);
break;
}
case MindType.Directory:
{
var port1 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Top, true) { XRatio = 0.5, YRatio = 0 };
this.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
this.AddConnector(port2);
break;
}
}
IsInnerConnector = true;
ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
case NodeLevel.Level3:
{
ItemWidth = 80;
ItemHeight = 25;
this.ClearConnectors();
switch (MindType)
{
case MindType.Mind:
case MindType.Logical:
{
var port1 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 1 };
this.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Right, true) { XRatio = 1, YRatio = 1 };
this.AddConnector(port2);
break;
}
case MindType.Directory:
{
var port1 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
this.AddConnector(port1);
var port2 = new FullyCreatedConnectorInfo(Root, this, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
this.AddConnector(port2);
break;
}
}
IsInnerConnector = true;
ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
break;
}
}
protected void InitLayout()
{
var layout = GlobalType.AllTypes.Where(p => typeof(IMindLayout).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == MindType.ToString() + "Layout");
MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout();
}
private bool Level_Enable(object obj)
{
if (Command_Enable(obj) == false) return false;
@@ -165,6 +73,10 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
#region
public IMindLayout MindLayout
{
get;set;
}
[Browsable(false)]
private NodeLevel _nodeLevel;
public NodeLevel NodeLevel
@@ -179,8 +91,21 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
}
private double _cornerRadius = 3;
public double CornerRadius
private MindType _mindType;
public MindType MindType
{
get
{
return _mindType;
}
set
{
SetProperty(ref _mindType, value);
}
}
private CornerRadius _cornerRadius = new CornerRadius(3);
public CornerRadius CornerRadius
{
get
{
@@ -192,6 +117,19 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
}
private Thickness _borderThickness = new Thickness(1);
public Thickness BorderThickness
{
get
{
return _borderThickness;
}
set
{
SetProperty(ref _borderThickness, value);
}
}
private bool _isExpanded = true;
public bool IsExpanded
{
@@ -247,19 +185,6 @@ namespace AIStudio.Wpf.Mind.ViewModels
get; set;
}
private MindType _mindType = MindType.Directory;
public MindType MindType
{
get
{
return _mindType;
}
set
{
SetProperty(ref _mindType, value);
}
}
private bool _isRightLayout = true;
public bool IsRightLayout
{
@@ -273,7 +198,10 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
}
private bool _layoutUpdating;
public bool LayoutUpdating
{
get;set;
}
#endregion
#region
@@ -604,20 +532,24 @@ namespace AIStudio.Wpf.Mind.ViewModels
case nameof(IsExpanded):
case nameof(ItemWidth):
case nameof(ItemHeight):
{
LayoutUpdated();
break;
}
case nameof(NodeLevel):
MindLayout?.Appearance(this);
break;
case nameof(MindType):
if (NodeLevel == NodeLevel.Level1)
{
LevelInit();
MindLayout?.Appearance(this);
LayoutUpdated();
}
else
{
GetLevel1Node().MindType = MindType;
}
break;
case nameof(NodeLevel):
LevelInit();
break;
break;
case nameof(Left):
{
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
@@ -654,7 +586,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
#region
protected MindNode GetLevel1Node()
public MindNode GetLevel1Node()
{
var node = this;
while (node.Parent is MindNode mindNode)
@@ -664,7 +596,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
return node;
}
protected MindNode GetLevel2Node()
public MindNode GetLevel2Node()
{
var node = this;
while (node.Parent is MindNode mindNode && mindNode.NodeLevel == NodeLevel.Level2)
@@ -676,262 +608,26 @@ namespace AIStudio.Wpf.Mind.ViewModels
protected void UpdateOffsetX(double oldvalue, double newvalue)
{
if (GetLevel1Node()?._layoutUpdating == true) return;
if (GetLevel1Node()?.LayoutUpdating == true) return;
Offset += new VectorBase(newvalue - oldvalue, 0);
}
protected void UpdateOffsetY(double oldvalue, double newvalue)
{
if (GetLevel1Node()?._layoutUpdating == true) return;
if (GetLevel1Node()?.LayoutUpdating == true) return;
Offset += new VectorBase(0, newvalue - oldvalue);
}
public void LayoutUpdated()
{
GetLevel1Node()?.Level1LayoutUpdated();
MindLayout?.LayoutUpdated(GetLevel1Node());
}
protected void Level1LayoutUpdated()
{
_layoutUpdating = true;
var size = MeasureOverride();
ArrangeOverride();
Root.BringToFrontCommand.Execute(new SelectableDesignerItemViewModelBase[] { this });
Root?.ReconnectLinksToClosestPorts();
_layoutUpdating = false;
}
protected SizeBase MeasureOverride(bool isExpanded = true)
{
switch (GetLevel1Node()?.MindType)
{
case MindType.Mind:
{
var sizewithSpacing = SizeWithSpacing;
if (Children?.Count > 0)
{
if (NodeLevel == NodeLevel.Level1)
{
var rights = Children.Where((p, index) => index % 2 == 0).ToList();
rights.ForEach(p => p.IsRightLayout = true);
var rightsizes = rights.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
var lefts = Children.Where((p, index) => index % 2 == 1).ToList();
lefts.ForEach(p => p.IsRightLayout = false);
var leftsizes = lefts.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + rightsizes.Max(p => p.Width) + +leftsizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, Math.Max(rightsizes.Sum(p => p.Height), leftsizes.Sum(p => p.Height))));
}
else
{
var childrensizes = Children.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
}
}
DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
Visible = isExpanded;
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
connectors?.ForEach(p => p.Visible = Visible);
break;
}
case MindType.Logical:
{
var sizewithSpacing = SizeWithSpacing;
if (Children?.Count > 0)
{
var childrensizes = Children.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
}
DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
Visible = isExpanded;
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
connectors?.ForEach(p => p.Visible = Visible);
break;
}
case MindType.Directory:
{
var sizewithSpacing = SizeWithSpacing;
if (Children?.Count > 0)
{
if (NodeLevel == NodeLevel.Level1)
{
var childrensizes = Children.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.Sum(p => p.Width)), sizewithSpacing.Height + childrensizes.Max(p => p.Height));
}
else
{
var childrensizes = Children.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width * 0.5 + childrensizes.Max(p => p.Width), sizewithSpacing.Height + childrensizes.Sum(p => p.Height));
}
}
DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
Visible = isExpanded;
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
connectors?.ForEach(p => p.Visible = Visible);
break;
}
default:
{
var sizewithSpacing = SizeWithSpacing;
if (Children?.Count > 0)
{
var childrensizes = Children.Select(p => p.MeasureOverride(IsExpanded && isExpanded)).ToArray();
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
}
DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
Visible = isExpanded;
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
connectors?.ForEach(p => p.Visible = Visible);
break;
}
}
return DesiredSize;
}
protected void ArrangeOverride()
{
switch (GetLevel1Node()?.MindType)
{
case MindType.Mind:
{
if (NodeLevel == NodeLevel.Level1)
{
if (Children?.Count > 0)
{
var rights = Children.Where(p => p.IsRightLayout == true).ToList();
double left = MiddlePosition.X + ItemWidth / 2 + Spacing.Width;
double lefttop = MiddlePosition.Y - Math.Min(DesiredSize.Height, rights.Sum(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;
lefttop += child.DesiredSize.Height;
child.ArrangeOverride();
}
var lefts = Children.Where(p => p.IsRightLayout == false).ToList();
double right = MiddlePosition.X - ItemWidth / 2 - Spacing.Width;
double righttop = MiddlePosition.Y - Math.Min(DesiredSize.Height, lefts.Sum(p => p.DesiredSize.Height)) / 2;
foreach (var child in lefts)
{
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;
righttop += child.DesiredSize.Height;
child.ArrangeOverride();
}
}
}
else
{
if (GetLevel2Node().IsRightLayout)
{
double left = MiddlePosition.X + ItemWidth / 2 + Spacing.Width;
double top = MiddlePosition.Y - Math.Min(DesiredSize.Height, Children.Sum(p => p.DesiredSize.Height)) / 2;
if (Children?.Count > 0)
{
foreach (var child in Children)
{
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;
top += child.DesiredSize.Height;
child.ArrangeOverride();
}
}
}
else
{
double right = MiddlePosition.X - ItemWidth / 2 - Spacing.Width;
double top = MiddlePosition.Y - Math.Min(DesiredSize.Height, Children.Sum(p => p.DesiredSize.Height)) / 2;
if (Children?.Count > 0)
{
foreach (var child in Children)
{
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;
top += child.DesiredSize.Height;
child.ArrangeOverride();
}
}
}
}
break;
}
case MindType.Logical:
{
double left = MiddlePosition.X + ItemWidth / 2 + Spacing.Width;
double top = MiddlePosition.Y - Math.Min(DesiredSize.Height, Children.Sum(p => p.DesiredSize.Height)) / 2;
if (Children?.Count > 0)
{
foreach (var child in Children)
{
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;
top += child.DesiredSize.Height;
child.ArrangeOverride();
}
}
break;
}
case MindType.Directory:
{
if (NodeLevel == NodeLevel.Level1)
{
double left = MiddlePosition.X - Math.Max(DesiredSize.Width, Children.Sum(p => p.DesiredSize.Width)) / 2;
double top = MiddlePosition.Y + ItemHeight / 2 + Spacing.Height;
if (Children?.Count > 0)
{
foreach (var child in Children)
{
child.Left = left + child.Spacing.Width + child.Offset.X;
child.Top = top + child.Spacing.Height + child.Offset.Y;
child.DesiredPosition = child.Position;
left += child.DesiredSize.Width;
child.ArrangeOverride();
}
}
}
else
{
double left = MiddlePosition.X;
double top = MiddlePosition.Y + ItemHeight / 2 + Spacing.Height;
if (Children?.Count > 0)
{
foreach (var child in Children)
{
child.Left = left + child.Offset.X;
child.Top = top + child.Spacing.Height + child.Offset.Y;
child.DesiredPosition = child.Position;
top += child.DesiredSize.Height;
child.ArrangeOverride();
}
}
}
break;
}
default:
{
break;
}
}
}
#endregion
}
public class LinkInfo : BindableBase
{
private string _url;