diff --git a/AIStudio.Wpf.Mind/Themes/MindNode.xaml b/AIStudio.Wpf.Mind/Themes/MindNode.xaml
index 445caea..b2eef5f 100644
--- a/AIStudio.Wpf.Mind/Themes/MindNode.xaml
+++ b/AIStudio.Wpf.Mind/Themes/MindNode.xaml
@@ -135,7 +135,7 @@
-
+
diff --git a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs
index a2c1847..5c574b5 100644
--- a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs
+++ b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs
@@ -5,6 +5,7 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
+using System.Windows.Controls;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
@@ -42,7 +43,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
AddChildCommand = new SimpleCommand(Command_Enable, ExecuteAddChildCommand);
AddParentCommand = new SimpleCommand(Level_Enable, ExecuteAddParentCommand);
AddPeerCommand = new SimpleCommand(Level_Enable, ExecuteAddPeerCommand);
- DeleteCommand = new SimpleCommand(Command_Enable, ExecuteDeleteCommand);
+ DeleteCommand = new SimpleCommand(Level_Enable, ExecuteDeleteCommand);
MoveForwardCommand = new SimpleCommand(Command_Enable, ExecuteMoveForwardCommand);
MoveBackCommand = new SimpleCommand(Command_Enable, ExecuteMoveBackCommand);
BuildMenuOptions();
@@ -50,7 +51,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
this.PropertyChanged += this.Item_PropertyChanged;
}
- private void LevelInit(bool init =false)
+ private void LevelInit(bool init = false)
{
switch (NodeLevel)
{
@@ -108,8 +109,6 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
}
-
-
private bool Level_Enable(object obj)
{
if (Command_Enable(obj) == false) return false;
@@ -117,10 +116,19 @@ namespace AIStudio.Wpf.Mind.ViewModels
return NodeLevel != NodeLevel.Level1;
}
+ #region 属性
[Browsable(false)]
+ private NodeLevel _nodeLevel;
public NodeLevel NodeLevel
{
- get; set;
+ get
+ {
+ return _nodeLevel;
+ }
+ set
+ {
+ SetProperty(ref _nodeLevel, value);
+ }
}
private double _cornerRadius = 3;
@@ -147,12 +155,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
{
SetProperty(ref _isExpanded, value);
}
- }
-
- public bool LayoutUpdating
- {
- get; set;
- }
+ }
public SizeBase Spacing
{
@@ -187,6 +190,25 @@ namespace AIStudio.Wpf.Mind.ViewModels
get; set;
}
+ private MindType _mindType;
+ public MindType MindType
+ {
+ get
+ {
+ return _mindType;
+ }
+ set
+ {
+ SetProperty(ref _mindType, value);
+ }
+ }
+
+ private bool _layoutUpdating;
+
+ private bool _isRightLayout = true;
+ #endregion
+
+ #region 命令
public SimpleCommand AddParentCommand
{
get; private set;
@@ -216,7 +238,9 @@ namespace AIStudio.Wpf.Mind.ViewModels
{
get; private set;
}
+ #endregion
+ #region 菜单
private void BuildMenuOptions()
{
menuOptions = new ObservableCollection();
@@ -228,10 +252,10 @@ namespace AIStudio.Wpf.Mind.ViewModels
menuItem.Text = "同级";
menuItem.Command = AddPeerCommand;
menuOptions.Add(menuItem);
- //menuItem = new CinchMenuItem();
- //menuItem.Text = "上级";
- //menuItem.Command = AddParentCommand;
- //menuOptions.Add(menuItem);
+ menuItem = new CinchMenuItem();
+ menuItem.Text = "上级";
+ menuItem.Command = AddParentCommand;
+ menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "前移";
menuItem.Command = MoveForwardCommand;
@@ -245,7 +269,9 @@ namespace AIStudio.Wpf.Mind.ViewModels
menuItem.Command = DeleteCommand;
menuOptions.Add(menuItem);
}
+ #endregion
+ #region 操作
public void ExecuteAddChildCommand(object obj)
{
if (obj is MindNode node)
@@ -285,6 +311,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
parent.RemoveChild(this);
int index = parent.Children.IndexOf(this);
parent.AddChild(node, index + 1);
+
node.AddChild(this);
LayoutUpdated();
@@ -348,13 +375,21 @@ namespace AIStudio.Wpf.Mind.ViewModels
{
if (Parent is MindNode parent)
{
- parent.RemoveChild(this);
+ parent.RemoveChild(this, true);
LayoutUpdated();
}
}
public void AddChild(MindNode item, int index = -1)
{
+ if (this.NodeLevel == NodeLevel.Level1)
+ {
+ item.NodeLevel = NodeLevel.Level2;
+ }
+ else
+ {
+ item.NodeLevel = NodeLevel.Level3;
+ }
if (index >= 0)
{
this.Children.Insert(index, item);
@@ -364,7 +399,6 @@ namespace AIStudio.Wpf.Mind.ViewModels
this.Children.Add(item);
}
item.Parent = this;
- //item.ParentId = this.Id;
Root?.DirectAddItemCommand.Execute(item);
ConnectionViewModel connector = new ConnectionViewModel(Root, this.Connectors.FirstOrDefault(), item.Connectors.FirstOrDefault());
@@ -375,13 +409,12 @@ namespace AIStudio.Wpf.Mind.ViewModels
connector.ShapeViewModel.SinkMarker.SizeStyle = this.ShapeViewModel.SinkMarker.SizeStyle;
Root?.DirectAddItemCommand.Execute(connector);
+ Root?.ClearSelectedItemsCommand.Execute(new SelectableDesignerItemViewModelBase[] { connector });
Root?.BringForwardCommand.Execute(new DesignerItemViewModelBase[] { item });
-
- Root?.ClearSelectedItemsCommand.Execute(new SelectableDesignerItemViewModelBase[] { connector });
}
- public void RemoveChild(MindNode item)
+ public void RemoveChild(MindNode item, bool removeall = false)
{
item.PropertyChanged -= Item_PropertyChanged;
@@ -391,30 +424,28 @@ namespace AIStudio.Wpf.Mind.ViewModels
Root?.DirectRemoveItemCommand.Execute(item);
Root?.DirectRemoveItemCommand.Execute(connectors);
- if (item.Children?.Count > 0)
+
+ if (removeall)
{
- foreach (var child in item.Children.ToList())
+ if (item.Children?.Count > 0)
{
- item.RemoveChild(child);
+ foreach (var child in item.Children.ToList())
+ {
+ item.RemoveChild(child);
+ }
}
}
}
-
- public MindNode GetLevel1Node()
- {
- var node = this;
- while (node.Parent is MindNode mindNode)
- {
- node = mindNode;
- }
- return node;
- }
+ #endregion
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(IsExpanded):
+ case nameof(ItemWidth):
+ case nameof(ItemHeight):
+ case nameof(MindType):
GetLevel1Node()?.LayoutUpdated();
break;
case nameof(NodeLevel):
@@ -422,7 +453,6 @@ namespace AIStudio.Wpf.Mind.ViewModels
break;
case nameof(Left):
{
-
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
{
if (NodeLevel == NodeLevel.Level1)
@@ -456,16 +486,37 @@ namespace AIStudio.Wpf.Mind.ViewModels
}
}
- public void UpdateOffsetX(double oldvalue, double newvalue)
+ #region 布局相关
+ protected MindNode GetLevel1Node()
{
- if (GetLevel1Node()?.LayoutUpdating == true) return;
+ var node = this;
+ while (node.Parent is MindNode mindNode)
+ {
+ node = mindNode;
+ }
+ return node;
+ }
+
+ protected MindNode GetLevel2Node()
+ {
+ var node = this;
+ while (node.Parent is MindNode mindNode && mindNode.NodeLevel == NodeLevel.Level2)
+ {
+ node = mindNode;
+ }
+ return node;
+ }
+
+ protected void UpdateOffsetX(double oldvalue, double newvalue)
+ {
+ if (GetLevel1Node()?._layoutUpdating == true) return;
Offset += new VectorBase(newvalue - oldvalue, 0);
}
- public void UpdateOffsetY(double oldvalue, double newvalue)
+ protected void UpdateOffsetY(double oldvalue, double newvalue)
{
- if (GetLevel1Node()?.LayoutUpdating == true) return;
+ if (GetLevel1Node()?._layoutUpdating == true) return;
Offset += new VectorBase(0, newvalue - oldvalue);
}
@@ -477,48 +528,180 @@ namespace AIStudio.Wpf.Mind.ViewModels
protected void Level1LayoutUpdated()
{
- LayoutUpdating = true;
+ _layoutUpdating = true;
var size = MeasureOverride();
ArrangeOverride();
Root.BringToFrontCommand.Execute(new SelectableDesignerItemViewModelBase[] { this });
Root?.ReconnectLinksToClosestPorts();
- LayoutUpdating = false;
+ _layoutUpdating = false;
}
protected SizeBase MeasureOverride(bool isExpanded = true)
{
- var sizewithSpacing = SizeWithSpacing;
- if (Children?.Count > 0)
+ switch (MindType)
{
- 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)));
+ 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().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().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().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
+ connectors?.ForEach(p => p.Visible = Visible);
+ break;
+ }
}
- DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
- Visible = isExpanded;
- var connectors = Root?.Items.OfType().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
- connectors?.ForEach(p => p.Visible = Visible);
return DesiredSize;
}
protected void ArrangeOverride()
{
- double left = MiddlePosition.X + ItemWidth / 2 + Spacing.Width;
- double top = MiddlePosition.Y - DesiredSize.Height / 2;
- if (Children?.Count > 0)
+ switch (MindType)
{
- foreach (var child in Children)
- {
+ 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.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();
+ }
- 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;
+ }
+ default:
+ {
+ break;
+ }
}
}
+ #endregion
}
}