Skip to content

Commit

Permalink
Fixed Node IsSelected property
Browse files Browse the repository at this point in the history
Fixed Node BorderBrush Style
Added AlignmentLine hint
  • Loading branch information
MakesYT committed Jan 31, 2024
1 parent b2b4802 commit cf54e0b
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 71 deletions.
1 change: 0 additions & 1 deletion NodifyM.Avalonia.Example/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@
<controls:Node.Styles>
<Style Selector="controls|Node[IsSelected=False]:pointerover">
<Setter Property="BorderBrush" Value="AliceBlue"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>
</Style>
</controls:Node.Styles>
<controls:Node.InputConnectorTemplate>
Expand Down
29 changes: 24 additions & 5 deletions NodifyM.Avalonia/Controls/BaseNode.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ namespace NodifyM.Avalonia.Controls;
public class BaseNode : ContentControl
{
public static readonly AvaloniaProperty<Point> LocationProperty =
AvaloniaProperty.Register<Node, Point>(nameof(Location));
public static readonly RoutedEvent LocationChangedEvent = RoutedEvent.Register<RoutedEventArgs>(nameof(LocationChanged), RoutingStrategies.Bubble, typeof(Node));
AvaloniaProperty.Register<BaseNode, Point>(nameof(Location));
public static readonly RoutedEvent LocationChangedEvent = RoutedEvent.Register<RoutedEventArgs>(nameof(LocationChanged), RoutingStrategies.Bubble, typeof(BaseNode));
public static readonly AvaloniaProperty<bool> IsSelectedProperty =
AvaloniaProperty.Register<BaseNode, bool>(nameof(IsSelected));
public bool IsSelected
{
get => (bool)GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
public event EventHandler<RoutedEventArgs> LocationChanged
{
add => AddHandler(LocationChangedEvent, value);
Expand Down Expand Up @@ -63,9 +70,14 @@ private void OnPointerPressed(object sender, PointerPressedEventArgs e)
foreach (var visual in parent)
{
visual.ZIndex = 0;

var first = visual.GetVisualChildren().First();
if (first is BaseNode baseNode)
{
baseNode.IsSelected = false;
}
}
visualParent.ZIndex = 1;
this.IsSelected = true;
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
// 启动拖动
isDragging = true;
Expand All @@ -88,7 +100,7 @@ private void OnPointerReleased(object sender, PointerReleasedEventArgs e)
isDragging = false;
e.Handled = true;
// 停止计时器

_editor.ClearAlignmentLine();

// var currentPoint = e.GetCurrentPoint(this);
// Debug.WriteLine($"停止拖动坐标X:{OffsetX} Y:{OffsetY}");
Expand All @@ -105,7 +117,14 @@ private void OnPointerMoved(object sender, PointerEventArgs e)
var currentMousePosition = e.GetPosition(((Visual)this.GetLogicalParent()).GetVisualParent());
var offset = currentMousePosition - lastMousePosition;

((BaseNodeViewModel)DataContext).Location = e.KeyModifiers.HasFlag(KeyModifiers.Shift) ? new Point((offset.X + _startOffsetX), offset.Y + _startOffsetY) : _editor.TryAlignNode(this,new Point((offset.X + _startOffsetX), offset.Y + _startOffsetY));
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
{
_editor.ClearAlignmentLine();
((BaseNodeViewModel)DataContext).Location = new Point((offset.X + _startOffsetX), offset.Y + _startOffsetY);
}
else
((BaseNodeViewModel)DataContext).Location = _editor.TryAlignNode(this,
new Point((offset.X + _startOffsetX), offset.Y + _startOffsetY));

RaiseEvent(new RoutedEventArgs(LocationChangedEvent,this));
}
Expand Down
2 changes: 1 addition & 1 deletion NodifyM.Avalonia/Controls/KnotNode.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
CornerRadius="3">
<ContentPresenter x:Name="PART_Connector" x:DataType="viewModelBase:KnotNodeViewModel" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"
<ContentPresenter Cursor="Arrow" x:Name="PART_Connector" x:DataType="viewModelBase:KnotNodeViewModel" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"
DataContext="{ReflectionBinding Path=Connector}"/>
</Border>
</ControlTemplate>
Expand Down
4 changes: 2 additions & 2 deletions NodifyM.Avalonia/Controls/Node.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

<Style Selector="controls|Node">
<Setter Property="BorderBrush" Value="{StaticResource Node.BorderBrush}"></Setter>

<Setter Property="Background" Value="{StaticResource Node.BackgroundBrush}"></Setter>
<Setter Property="HeaderBrush" Value="{StaticResource Node.HeaderBrush}"></Setter>
<Setter Property="FooterBrush" Value="{StaticResource Node.FooterBrush}"></Setter>
Expand Down Expand Up @@ -104,10 +105,9 @@
</Style>
<Style Selector="controls|Node[IsSelected=False]:pointerover">
<Setter Property="BorderBrush" Value="LightBlue"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>

</Style>
<Style Selector="controls|Node[IsSelected=True]">
<Setter Property="BorderBrush" Value="Orange"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>
</Style>
</Styles>
8 changes: 1 addition & 7 deletions NodifyM.Avalonia/Controls/Node.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,7 @@ public class Node : BaseNode
public static readonly AvaloniaProperty<IEnumerable> OutputProperty =
AvaloniaProperty.Register<Node, IEnumerable>(nameof(Output));

public static readonly AvaloniaProperty<bool> IsSelectedProperty =
AvaloniaProperty.Register<Node, bool>(nameof(IsSelected));
public bool IsSelected
{
get => (bool)GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}


public Brush ContentBrush
{
Expand Down
6 changes: 3 additions & 3 deletions NodifyM.Avalonia/Controls/NodifyEditor.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Canvas Background="{StaticResource NodifyEditor.BackgroundBrush}" >
<ItemsPresenter Canvas.Top="{TemplateBinding OffsetY}" Canvas.Left="{TemplateBinding OffsetX}" ItemsPanel="{TemplateBinding ItemsPanel}" />
<Canvas Background="{StaticResource NodifyEditor.BackgroundBrush}" >
<ItemsPresenter RenderTransform="{TemplateBinding ViewTranslateTransform}" ItemsPanel="{TemplateBinding ItemsPanel}" />
<ContentPresenter ZIndex="-2" ContentTemplate="{TemplateBinding GridLineTemplate}"/>
<ContentPresenter Name="PendingConnection" Content="{TemplateBinding PendingConnection}"
ContentTemplate="{TemplateBinding PendingConnectionTemplate}" />
Expand Down Expand Up @@ -61,7 +61,7 @@
<ItemsControl.Styles>
<Style Selector="ItemsControl">
<Setter Property="ZIndex"
Value="-1" />
Value="2" />
</Style>
</ItemsControl.Styles>
<ItemsControl.ItemsPanel>
Expand Down
165 changes: 118 additions & 47 deletions NodifyM.Avalonia/Controls/NodifyEditor.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Avalonia.VisualTree;
using NodifyM.Avalonia.Events;
using NodifyM.Avalonia.Helpers;
using NodifyM.Avalonia.ViewModelBase;

namespace NodifyM.Avalonia.Controls;

Expand Down Expand Up @@ -355,7 +356,7 @@ private void OnRemoveConnection(object sender, ConnectionEventArgs e)
public static readonly AvaloniaProperty<bool> AllowAlignProperty = AvaloniaProperty.Register<NodifyEditor, bool>(nameof(AllowAlign),BoxValue.True);

public static readonly StyledProperty<IDataTemplate> AlignmentLineTemplateProperty = AvaloniaProperty.Register<NodifyEditor,IDataTemplate>(nameof(AlignmentLineTemplate));
public static readonly StyledProperty<AvaloniaList<object>> AlignmentLineProperty = AvaloniaProperty.Register<NodifyEditor, AvaloniaList<object>>(nameof(AlignmentLine));
public static readonly StyledProperty<AvaloniaList<object>> AlignmentLineProperty = AvaloniaProperty.Register<NodifyEditor, AvaloniaList<object>>(nameof(AlignmentLine),new AvaloniaList<object>());
public AvaloniaList<object> AlignmentLine
{
get => GetValue(AlignmentLineProperty);
Expand All @@ -377,6 +378,10 @@ public bool AllowAlign
get => (bool)GetValue(AllowAlignProperty);
set => SetValue(AllowAlignProperty, value);
}
public void ClearAlignmentLine()
{
AlignmentLine.Clear();
}
public Point TryAlignNode(BaseNode control,Point point)
{
AlignmentLine.Clear();
Expand All @@ -386,7 +391,8 @@ public Point TryAlignNode(BaseNode control,Point point)
double y = (int)point.Y;
double nowIntervalX = AlignmentRange;
double nowIntervalY = AlignmentRange;

var movingNodeWidth = control.Bounds.Width;
var movingNodeHeight = control.Bounds.Height;
if (ItemsPanelRoot?.Children == null) return point;
foreach (var child in ItemsPanelRoot?.Children)
{
Expand All @@ -395,76 +401,141 @@ public Point TryAlignNode(BaseNode control,Point point)
{
continue;
}

// 合并两个区域的代码
var regionX = node.Location.X;
var regionY = node.Location.Y;
var controlWidth = control.Bounds.Width;
var controlHeight = control.Bounds.Height;

// 计算左上角区域的边界
var intervalX = Math.Abs(regionX - x);
if (intervalX < nowIntervalX)
var nodeLocationX = node.Location.X;
var nodeLocationY = node.Location.Y;
var nodeWidth = node.Bounds.Width;
var nodeHeight = node.Bounds.Height;

//上->上
var intervalY = Math.Abs(nodeLocationY - y);
if (intervalY <= nowIntervalY)
{
x = regionX;

nowIntervalX = intervalX;
y = nodeLocationY;
nowIntervalY = intervalY;
AlignmentLine.Add(x <= nodeLocationX
? new AlignmentLineViewModel(new Point(nodeLocationX + nodeWidth, y ), new Point(control.Location.X, y ))
: new AlignmentLineViewModel(new Point(nodeLocationX, y ),
new Point(control.Location.X + movingNodeWidth, y )));
}

var intervalX2 = Math.Abs(regionX + node.Bounds.Width - x);
if (intervalX2 < nowIntervalX)
//上->下
var intervalY3 = Math.Abs(nodeLocationY - movingNodeHeight - y);
if (intervalY3 <= nowIntervalY)
{
x = regionX + node.Bounds.Width;
nowIntervalX = intervalX2;
y = nodeLocationY - movingNodeHeight;
nowIntervalY = intervalY3;
AlignmentLine.Add(x <= nodeLocationX
? new AlignmentLineViewModel(new Point(nodeLocationX + nodeWidth, nodeLocationY ), new Point(control.Location.X, nodeLocationY ))
: new AlignmentLineViewModel(new Point(nodeLocationX, nodeLocationY ),
new Point(control.Location.X + movingNodeWidth, nodeLocationY )));
}

var intervalY = Math.Abs(regionY - y);
if (intervalY < nowIntervalY)
//下->下
var intervalY4 = Math.Abs(nodeLocationY - movingNodeHeight + nodeHeight - y);
if (intervalY4 <= nowIntervalY)
{
y = regionY;
nowIntervalY = intervalY;
y = nodeLocationY - movingNodeHeight + nodeHeight;
nowIntervalY = intervalY4;
AlignmentLine.Add(x <= nodeLocationX
? new AlignmentLineViewModel(new Point(nodeLocationX + nodeWidth, y+movingNodeHeight ), new Point(control.Location.X, y+movingNodeHeight ))
: new AlignmentLineViewModel(new Point(nodeLocationX, y+movingNodeHeight ),
new Point(control.Location.X + movingNodeWidth, y+movingNodeHeight )));
}

var intervalY2 = Math.Abs(regionY + node.Bounds.Height - y);
if (intervalY2 < nowIntervalY)
//下->上
var intervalY2 = Math.Abs(nodeLocationY + nodeHeight - y);
if (intervalY2 <= nowIntervalY)
{
y = regionY + node.Bounds.Height;

y = nodeLocationY + nodeHeight;
nowIntervalY = intervalY2;
AlignmentLine.Add(x <= nodeLocationX
? new AlignmentLineViewModel(new Point(nodeLocationX + nodeWidth, y ), new Point(control.Location.X, y ))
: new AlignmentLineViewModel(new Point(nodeLocationX, y ),
new Point(control.Location.X + movingNodeWidth, y )));
}

// 计算右下角区域的边界
var intervalX3 = Math.Abs(regionX - controlWidth - x);
if (intervalX3 < nowIntervalX)
//左->右
var intervalX3 = Math.Abs(nodeLocationX - movingNodeWidth - x);
if (intervalX3 <= nowIntervalX)
{
x = regionX - controlWidth;
x = nodeLocationX - movingNodeWidth;
nowIntervalX = intervalX3;
AlignmentLine.Add(y <= nodeLocationY
? new AlignmentLineViewModel(new Point(x+movingNodeWidth, control.Location.Y),
new Point(x+movingNodeWidth, nodeLocationY+nodeHeight))
: new AlignmentLineViewModel(new Point(x+movingNodeWidth, control.Location.Y+movingNodeHeight),
new Point(x+movingNodeWidth, nodeLocationY)));
}

var intervalX4 = Math.Abs(regionX - controlWidth + node.Bounds.Width - x);
if (intervalX4 < nowIntervalX)

//左->左
var intervalX = Math.Abs(nodeLocationX - x);
if (intervalX <= nowIntervalX)
{
x = regionX - controlWidth + node.Bounds.Width;
x = nodeLocationX;
nowIntervalX = intervalX;
AlignmentLine.Add(y <= nodeLocationY
? new AlignmentLineViewModel(new Point(x, control.Location.Y),
new Point(x, nodeLocationY+nodeHeight))
: new AlignmentLineViewModel(new Point(x, control.Location.Y+movingNodeHeight),
new Point(x, nodeLocationY)));
}
//右->右
var intervalX4 = Math.Abs(nodeLocationX - movingNodeWidth + nodeWidth - x);
if (intervalX4 <= nowIntervalX)
{
x = nodeLocationX - movingNodeWidth + nodeWidth;
nowIntervalX = intervalX4;
AlignmentLine.Add(y <= nodeLocationY
? new AlignmentLineViewModel(new Point(x+movingNodeWidth, control.Location.Y),
new Point(x+movingNodeWidth, nodeLocationY+nodeHeight))
: new AlignmentLineViewModel(new Point(x+movingNodeWidth, control.Location.Y+movingNodeHeight),
new Point(x+movingNodeWidth, nodeLocationY)));
}

var intervalY3 = Math.Abs(regionY - controlHeight - y);
if (intervalY3 < nowIntervalY)
//右->左
var intervalX2 = Math.Abs(nodeLocationX + nodeWidth - x);
if (intervalX2 <= nowIntervalX)
{
y = regionY - controlHeight;
nowIntervalY = intervalY3;
x = nodeLocationX + nodeWidth;
nowIntervalX = intervalX2;
AlignmentLine.Add(y <= nodeLocationY
? new AlignmentLineViewModel(new Point(x, control.Location.Y),
new Point(x, nodeLocationY+nodeHeight))
: new AlignmentLineViewModel(new Point(x, control.Location.Y+movingNodeHeight),
new Point(x, nodeLocationY)));
}


}

var intervalY4 = Math.Abs(regionY - controlHeight + node.Bounds.Height - y);
if (intervalY4 < nowIntervalY)
for (var index = AlignmentLine.Count - 1; index >= 0; index--)
{
var o = AlignmentLine[index];
if (o is AlignmentLineViewModel alignmentLineViewModel)
{
y = regionY - controlHeight + node.Bounds.Height;
nowIntervalY = intervalY4;
if (alignmentLineViewModel.Start.X.Equals(alignmentLineViewModel.End.X))
{
//竖向
if (!alignmentLineViewModel.Start.X.Equals(x)&&!alignmentLineViewModel.Start.X.Equals(x+movingNodeWidth))
{
AlignmentLine.RemoveAt(index);
}
}

if (alignmentLineViewModel.Start.Y.Equals(alignmentLineViewModel.End.Y))
{
//横向
if (!alignmentLineViewModel.Start.Y.Equals(y)&&!alignmentLineViewModel.Start.Y.Equals(y+movingNodeHeight))
{
AlignmentLine.RemoveAt(index);
}
}
}
}

return new Point(x, y);

}


#endregion
}
2 changes: 1 addition & 1 deletion NodifyM.Avalonia/ResourceDictionaries/Dark.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<Color x:Key="Node.HeaderForegroundColor">White</Color>
<Color x:Key="Node.HeaderColor">#1E1E1E</Color>
<Color x:Key="Node.FooterColor">#1E1E1E</Color>
<Color x:Key="Node.BorderColor">Transparent</Color>
<Color x:Key="Node.BorderColor">#2D2D30</Color>

<!--STATE NODE-->
<Color x:Key="StateNode.BackgroundColor">#171717</Color>
Expand Down
2 changes: 1 addition & 1 deletion NodifyM.Avalonia/ResourceDictionaries/Light.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<Color x:Key="Node.HeaderForegroundColor">White</Color>
<Color x:Key="Node.HeaderColor">#5C6A98</Color>
<Color x:Key="Node.FooterColor">#5C6A98</Color>
<Color x:Key="Node.BorderColor">Transparent</Color>
<Color x:Key="Node.BorderColor">#CBCCDF</Color>

<!--STATE NODE-->
<Color x:Key="StateNode.BackgroundColor">#5C6A98</Color>
Expand Down
2 changes: 1 addition & 1 deletion NodifyM.Avalonia/ResourceDictionaries/Nodify.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<controls:NodeOutput />
</DataTemplate>
<DataTemplate x:Key="AlignmentLineTemplate" DataType="viewModelBase:AlignmentLineViewModel">
<Line StrokeThickness="0.5" Stroke="{StaticResource NodifyEditor.AlignmentLineBrush}"
<Line StrokeThickness="1" Stroke="{StaticResource NodifyEditor.AlignmentLineBrush}"
StartPoint="{Binding Start}"
EndPoint="{Binding End}"
IsVisible="{Binding IsVisible}"
Expand Down
Loading

0 comments on commit cf54e0b

Please sign in to comment.