Files
bluflame/intromat/NodeNetwork/Views/PortView.cs
2026-04-18 22:31:51 +02:00

232 lines
8.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using NodeNetwork.ViewModels;
using NodeNetwork.Views.Controls;
using ReactiveUI;
namespace NodeNetwork.Views
{
[TemplateVisualState(Name = ConnectedState, GroupName = ConnectedVisualStatesGroup)]
[TemplateVisualState(Name = DisconnectedState, GroupName = ConnectedVisualStatesGroup)]
[TemplateVisualState(Name = HighlightedState, GroupName = HighlightVisualStatesGroup)]
[TemplateVisualState(Name = NonHighlightedState, GroupName = HighlightVisualStatesGroup)]
[TemplateVisualState(Name = ErrorState, GroupName = ErrorVisualStatesGroup)]
[TemplateVisualState(Name = NonErrorState, GroupName = ErrorVisualStatesGroup)]
public class PortView : Control, IViewFor<PortViewModel>
{
#region ViewModel
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(PortViewModel), typeof(PortView), new PropertyMetadata(null));
public PortViewModel ViewModel
{
get => (PortViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (PortViewModel)value;
}
#endregion
#region ConnectedStates
public const string ConnectedVisualStatesGroup = "ConnectedStates";
public const string ConnectedState = "Connected";
public const string DisconnectedState = "Disconnected";
#endregion
#region HighlightStates
public const string HighlightVisualStatesGroup = "HighlightStates";
public const string HighlightedState = "Highlighted";
public const string NonHighlightedState = "NonHighlighted";
#endregion
#region ErrorStates
public const string ErrorVisualStatesGroup = "ErrorStates";
public const string ErrorState = "Error";
public const string NonErrorState = "NoError";
#endregion
#region Brushes
#region RegularStroke
public Brush RegularStroke
{
get => (Brush)this.GetValue(RegularStrokeProperty);
set => this.SetValue(RegularStrokeProperty, value);
}
public static readonly DependencyProperty RegularStrokeProperty = DependencyProperty.Register(nameof(RegularStroke), typeof(Brush), typeof(PortView));
#endregion
#region RegularFill
public Brush RegularFill
{
get => (Brush)this.GetValue(RegularFillProperty);
set => this.SetValue(RegularFillProperty, value);
}
public static readonly DependencyProperty RegularFillProperty = DependencyProperty.Register(nameof(RegularFill), typeof(Brush), typeof(PortView));
#endregion
#region ConnectedStroke
public Brush ConnectedStroke
{
get => (Brush)this.GetValue(ConnectedStrokeProperty);
set => this.SetValue(ConnectedStrokeProperty, value);
}
public static readonly DependencyProperty ConnectedStrokeProperty = DependencyProperty.Register(nameof(ConnectedStroke), typeof(Brush), typeof(PortView));
#endregion
#region ConnectedFill
public Brush ConnectedFill
{
get => (Brush)this.GetValue(ConnectedFillProperty);
set => this.SetValue(ConnectedFillProperty, value);
}
public static readonly DependencyProperty ConnectedFillProperty = DependencyProperty.Register(nameof(ConnectedFill), typeof(Brush), typeof(PortView));
#endregion
#region HighlightStroke
public Brush HighlightStroke
{
get => (Brush)this.GetValue(HighlightStrokeProperty);
set => this.SetValue(HighlightStrokeProperty, value);
}
public static readonly DependencyProperty HighlightStrokeProperty = DependencyProperty.Register(nameof(HighlightStroke), typeof(Brush), typeof(PortView));
#endregion
#region HighlightFill
public Brush HighlightFill
{
get => (Brush)this.GetValue(HighlightFillProperty);
set => this.SetValue(HighlightFillProperty, value);
}
public static readonly DependencyProperty HighlightFillProperty = DependencyProperty.Register(nameof(HighlightFill), typeof(Brush), typeof(PortView));
#endregion
#region ErrorStroke
public Brush ErrorStroke
{
get => (Brush)this.GetValue(ErrorStrokeProperty);
set => this.SetValue(ErrorStrokeProperty, value);
}
public static readonly DependencyProperty ErrorStrokeProperty = DependencyProperty.Register(nameof(ErrorStroke), typeof(Brush), typeof(PortView));
#endregion
#region ErrorFill
public Brush ErrorFill
{
get => (Brush)this.GetValue(ErrorFillProperty);
set => this.SetValue(ErrorFillProperty, value);
}
public static readonly DependencyProperty ErrorFillProperty = DependencyProperty.Register(nameof(ErrorFill), typeof(Brush), typeof(PortView));
#endregion
#endregion
public PortView()
{
this.DefaultStyleKey = typeof(PortView);
}
public override void OnApplyTemplate()
{
VisualStateManager.GoToState(this, DisconnectedState, false);
VisualStateManager.GoToState(this, NonHighlightedState, false);
VisualStateManager.GoToState(this, NonErrorState, false);
SetupLayoutEvent();
SetupMouseEvents();
SetupVisualStateBindings();
}
private void SetupVisualStateBindings()
{
this.WhenActivated(d =>
{
this.WhenAnyObservable(v => v.ViewModel.Parent.Connections.CountChanged).Select(c => c == 0).Subscribe(isDisconnected =>
{
VisualStateManager.GoToState(this, isDisconnected ? DisconnectedState : ConnectedState, true);
}).DisposeWith(d);
this.WhenAnyValue(v => v.ViewModel.IsHighlighted).Subscribe(isHighlighted =>
{
VisualStateManager.GoToState(this, isHighlighted ? HighlightedState : NonHighlightedState, true);
}).DisposeWith(d);
this.WhenAnyValue(v => v.ViewModel.IsInErrorMode).Subscribe(isInErrorMode =>
{
VisualStateManager.GoToState(this, isInErrorMode ? ErrorState : NonErrorState, true);
}).DisposeWith(d);
});
}
protected virtual void SetupLayoutEvent()
{
this.WhenActivated(d =>
{
this.Events().LayoutUpdated.Subscribe(e =>
{
//Update endpoint center point
if (ViewModel == null)
{
return;
}
NetworkView networkView = WPFUtils.FindParent<NetworkView>(this);
if (networkView == null)
{
return;
}
Point center = new Point(this.ActualWidth / 2d, this.ActualHeight / 2d);
if (Margin.Left < 0)
{
center.X += Margin.Left;
}
else if (Margin.Right < 0)
{
center.X -= Margin.Right;
}
var transform = this.TransformToAncestor(networkView.contentContainer);
ViewModel.CenterPoint = transform.Transform(center);
}).DisposeWith(d);
});
}
private void SetupMouseEvents()
{
this.MouseLeftButtonDown += (sender, e) =>
{
e.Handled = true;
ViewModel.OnDragFromPort();
};
this.MouseEnter += (sender, e) =>
{
e.Handled = true;
ViewModel.OnPortEnter();
};
this.MouseLeave += (sender, e) =>
{
e.Handled = true;
ViewModel.OnPortLeave();
};
this.MouseLeftButtonUp += (sender, e) =>
{
e.Handled = true;
ViewModel.OnDropOnPort();
};
}
}
}