port from perforce
This commit is contained in:
228
intromat/NodeNetwork/Views/ConnectionView.cs
Normal file
228
intromat/NodeNetwork/Views/ConnectionView.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
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.Media;
|
||||
using System.Windows.Shapes;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplateVisualState(Name = HighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonHighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = ErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = MarkedForDeleteState, GroupName = MarkedForDeleteVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NotMarkedForDeleteState, GroupName = MarkedForDeleteVisualStatesGroup)]
|
||||
public class ConnectionView : Control, IViewFor<ConnectionViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(ConnectionViewModel), typeof(ConnectionView), new PropertyMetadata(null));
|
||||
|
||||
public ConnectionViewModel ViewModel
|
||||
{
|
||||
get => (ConnectionViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ConnectionViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region States
|
||||
#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 ErrorStates
|
||||
public const string MarkedForDeleteVisualStatesGroup = "MarkedForDeleteStates";
|
||||
public const string MarkedForDeleteState = "Marked";
|
||||
public const string NotMarkedForDeleteState = "NotMarked";
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region RegularBrush
|
||||
public Brush RegularBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(RegularBrushProperty);
|
||||
set => this.SetValue(RegularBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty RegularBrushProperty = DependencyProperty.Register(nameof(RegularBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region ErrorBrush
|
||||
public Brush ErrorBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ErrorBrushProperty);
|
||||
set => this.SetValue(ErrorBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ErrorBrushProperty = DependencyProperty.Register(nameof(ErrorBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region HighlightBrush
|
||||
public Brush HighlightBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(HighlightBrushProperty);
|
||||
set => this.SetValue(HighlightBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register(nameof(HighlightBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region MarkedForDeleteBrush
|
||||
public Brush MarkedForDeleteBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(MarkedForDeleteBrushProperty);
|
||||
set => this.SetValue(MarkedForDeleteBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty MarkedForDeleteBrushProperty =
|
||||
DependencyProperty.Register(nameof(MarkedForDeleteBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region Geometry
|
||||
public Geometry Geometry
|
||||
{
|
||||
get => (Geometry)this.GetValue(GeometryProperty);
|
||||
private set => this.SetValue(GeometryProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty GeometryProperty = DependencyProperty.Register(nameof(Geometry), typeof(Geometry), typeof(ConnectionView));
|
||||
#endregion
|
||||
|
||||
public ConnectionView()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(ConnectionView);
|
||||
|
||||
SetupPathData();
|
||||
SetupBrushesBinding();
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
VisualStateManager.GoToState(this, NonHighlightedState, false);
|
||||
VisualStateManager.GoToState(this, NonErrorState, false);
|
||||
VisualStateManager.GoToState(this, NotMarkedForDeleteState, false);
|
||||
}
|
||||
|
||||
private void SetupPathData()
|
||||
{
|
||||
this.WhenActivated(d => d(
|
||||
this.WhenAny(
|
||||
v => v.ViewModel.Input.Port.CenterPoint,
|
||||
v => v.ViewModel.Input.PortPosition,
|
||||
v => v.ViewModel.Output.Port.CenterPoint,
|
||||
v => v.ViewModel.Output.PortPosition,
|
||||
(a, b, c, e) => (a, b, c, e))
|
||||
.Select(_
|
||||
=> BuildSmoothBezier(
|
||||
ViewModel.Input.Port.CenterPoint,
|
||||
ViewModel.Input.PortPosition,
|
||||
ViewModel.Output.Port.CenterPoint,
|
||||
ViewModel.Output.PortPosition))
|
||||
.BindTo(this, v => v.Geometry)
|
||||
));
|
||||
}
|
||||
|
||||
private void SetupBrushesBinding()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.WhenAnyValue(v => v.ViewModel.IsHighlighted).Subscribe(isHighlighted =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isHighlighted ? HighlightedState : NonHighlightedState, true);
|
||||
}).DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel.IsInErrorState).Subscribe(isInErrorState =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isInErrorState ? ErrorState : NonErrorState, true);
|
||||
}).DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel.IsMarkedForDelete).Subscribe(isMarkedForDelete =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isMarkedForDelete ? MarkedForDeleteState : NotMarkedForDeleteState, true);
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, PortPosition startPosition, Point endPoint, PortPosition endPosition)
|
||||
{
|
||||
Vector startGradient = ToGradient(startPosition);
|
||||
Vector endGradient = ToGradient(endPosition);
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, PortPosition startPosition, Point endPoint)
|
||||
{
|
||||
Vector startGradient = ToGradient(startPosition);
|
||||
Vector endGradient = -startGradient;
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, Point endPoint, PortPosition endPosition)
|
||||
{
|
||||
Vector endGradient = ToGradient(endPosition);
|
||||
Vector startGradient = -endGradient;
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
private static Vector ToGradient(PortPosition portPosition)
|
||||
{
|
||||
switch (portPosition)
|
||||
{
|
||||
case PortPosition.Left:
|
||||
return new Vector(-1, 0);
|
||||
case PortPosition.Right:
|
||||
return new Vector(1, 0);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private const double MinGradient = 10;
|
||||
private const double WidthScaling = 5;
|
||||
|
||||
private static PathGeometry BuildSmoothBezier(Point startPoint, Vector startGradient, Point endPoint, Vector endGradient)
|
||||
{
|
||||
double width = endPoint.X - startPoint.X;
|
||||
|
||||
var gradientScale = Math.Sqrt(Math.Abs(width) * WidthScaling + MinGradient * MinGradient);
|
||||
|
||||
Point startGradientPoint = startPoint + startGradient * gradientScale;
|
||||
Point endGradientPoint = endPoint + endGradient * gradientScale;
|
||||
|
||||
Point midPoint = new Point((startGradientPoint.X + endGradientPoint.X) / 2d, (startPoint.Y + endPoint.Y) / 2d);
|
||||
|
||||
PathFigure pathFigure = new PathFigure
|
||||
{
|
||||
StartPoint = startPoint,
|
||||
IsClosed = false,
|
||||
Segments =
|
||||
{
|
||||
new QuadraticBezierSegment(startGradientPoint, midPoint, true),
|
||||
new QuadraticBezierSegment(endGradientPoint, endPoint, true)
|
||||
}
|
||||
};
|
||||
|
||||
PathGeometry geom = new PathGeometry();
|
||||
geom.Figures.Add(pathFigure);
|
||||
|
||||
return geom;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user