port from perforce
This commit is contained in:
270
intromat/Intromat/Views/CodeGenNodeView.cs
Normal file
270
intromat/Intromat/Views/CodeGenNodeView.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.Utilities;
|
||||
using NodeNetwork.ViewModels;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(NameLabel), Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = nameof(HeaderIcon), Type = typeof(Image))]
|
||||
[TemplatePart(Name = nameof(LeftList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(RightList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(ResizeVerticalThumb), Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = nameof(ResizeHorizontalThumb), Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = nameof(ResizeDiagonalThumb), Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = nameof(Preview), Type = typeof(ViewModelViewHost))]
|
||||
[TemplateVisualState(Name = SelectedState, GroupName = SelectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = UnselectedState, GroupName = SelectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = CollapsedState, GroupName = CollapsedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = ExpandedState, GroupName = CollapsedVisualStatesGroup)]
|
||||
public class CodeGenNodeView : NodeViewBase, IViewFor<CodeGenNodeViewModel>
|
||||
{
|
||||
private Size _previousSize;
|
||||
|
||||
public CodeGenNodeView()
|
||||
{
|
||||
DefaultStyleKey = typeof(CodeGenNodeView);
|
||||
|
||||
SetupBindings();
|
||||
SetupEvents();
|
||||
SetupVisualStateBindings();
|
||||
}
|
||||
|
||||
private TextBlock NameLabel { get; set; } = null!;
|
||||
private Image HeaderIcon { get; set; } = null!;
|
||||
private ItemsControl LeftList { get; set; } = null!;
|
||||
private ItemsControl RightList { get; set; } = null!;
|
||||
private Thumb ResizeVerticalThumb { get; set; } = null!;
|
||||
private Thumb ResizeHorizontalThumb { get; set; } = null!;
|
||||
private Thumb ResizeDiagonalThumb { get; set; } = null!;
|
||||
private ViewModelViewHost Preview { get; set; } = null!;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
ResizeHorizontalThumb = (Thumb)GetTemplateChild(nameof(ResizeHorizontalThumb))!;
|
||||
ResizeVerticalThumb = (Thumb)GetTemplateChild(nameof(ResizeVerticalThumb))!;
|
||||
LeftList = (ItemsControl)GetTemplateChild(nameof(LeftList))!;
|
||||
RightList = (ItemsControl)GetTemplateChild(nameof(RightList))!;
|
||||
HeaderIcon = (Image)GetTemplateChild(nameof(HeaderIcon))!;
|
||||
NameLabel = (TextBlock)GetTemplateChild(nameof(NameLabel))!;
|
||||
ResizeDiagonalThumb = (Thumb)GetTemplateChild(nameof(ResizeDiagonalThumb))!;
|
||||
Preview = (ViewModelViewHost)GetTemplateChild(nameof(Preview))!;
|
||||
|
||||
ResizeVerticalThumb.DragStarted += BeginResize;
|
||||
ResizeHorizontalThumb.DragStarted += BeginResize;
|
||||
ResizeDiagonalThumb.DragStarted += BeginResize;
|
||||
|
||||
ResizeVerticalThumb.DragCompleted += EndResize;
|
||||
ResizeHorizontalThumb.DragCompleted += EndResize;
|
||||
ResizeDiagonalThumb.DragCompleted += EndResize;
|
||||
|
||||
ResizeVerticalThumb.DragDelta += (_, e) => ApplyResize(e, false, true);
|
||||
ResizeHorizontalThumb.DragDelta += (_, e) => ApplyResize(e, true, false);
|
||||
ResizeDiagonalThumb.DragDelta += (_, e) => ApplyResize(e, true, true);
|
||||
|
||||
VisualStateManager.GoToState(this, ExpandedState, false);
|
||||
VisualStateManager.GoToState(this, UnselectedState, false);
|
||||
}
|
||||
|
||||
private void BeginResize(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
_previousSize = ViewModel!.Size;
|
||||
}
|
||||
|
||||
private void EndResize(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
var document = ((CodeGenNetworkViewModel)ViewModel!.Parent).Document;
|
||||
var undoRedo = document.MainViewModel.UndoRedo;
|
||||
undoRedo.Record(new UndoItem<NodeViewModel, Size>(document, ViewModel, vm => vm.Size, _previousSize, ViewModel.Size));
|
||||
}
|
||||
|
||||
private void ApplyResize(DragDeltaEventArgs e, bool horizontal, bool vertical)
|
||||
{
|
||||
if (horizontal)
|
||||
MinWidth = Math.Max(20, MinWidth + e.HorizontalChange);
|
||||
if (vertical)
|
||||
MinHeight = Math.Max(20, MinHeight + e.VerticalChange);
|
||||
}
|
||||
|
||||
private void SetupBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
var viewModel = ViewModel!;
|
||||
this.Events()
|
||||
.MouseEnter.Subscribe(_ => { viewModel.IsMouseOver = true; })
|
||||
.DisposeWith(d);
|
||||
this.Events()
|
||||
.MouseLeave.Subscribe(_ => { viewModel.IsMouseOver = false; })
|
||||
.DisposeWith(d);
|
||||
|
||||
this.OneWayBind(viewModel, vm => vm.Name, v => v.NameLabel.Text)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.BindList(viewModel, vm => vm.LeftEndpoints, v => v.LeftList.ItemsSource)
|
||||
.DisposeWith(d);
|
||||
this.BindList(viewModel, vm => vm.RightEndpoints, v => v.RightList.ItemsSource)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ActualWidth, v => v.ActualHeight, (width, height) => new Size(width, height))
|
||||
.BindTo(this, v => v.ViewModel!.Size)
|
||||
.DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel!.Size)
|
||||
.Subscribe(size =>
|
||||
{
|
||||
MinWidth = size.Width;
|
||||
MinHeight = size.Height;
|
||||
})
|
||||
.DisposeWith(d);
|
||||
|
||||
this.OneWayBind(viewModel, vm => vm.HeaderIcon, v => v.HeaderIcon.Source, img => img?.ToNative())
|
||||
.DisposeWith(d);
|
||||
this.OneWayBind(viewModel, vm => vm.NodeType, v => v.Background, ConvertNodeTypeToBrush)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.OneWayBind(viewModel, vm => vm.Preview, v => v.Preview.ViewModel)
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupEvents()
|
||||
{
|
||||
MouseLeftButtonDown += (_, _) =>
|
||||
{
|
||||
Focus();
|
||||
|
||||
if (ViewModel == null)
|
||||
return;
|
||||
|
||||
if (ViewModel.IsSelected)
|
||||
return;
|
||||
|
||||
if (ViewModel.Parent != null && !Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
ViewModel.Parent.ClearSelection();
|
||||
|
||||
ViewModel.IsSelected = true;
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupVisualStateBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.WhenAnyValue(v => v.ViewModel!.IsCollapsed)
|
||||
.Subscribe(isCollapsed => { VisualStateManager.GoToState(this, isCollapsed ? CollapsedState : ExpandedState, true); })
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel!.IsSelected)
|
||||
.Subscribe(isSelected => { VisualStateManager.GoToState(this, isSelected ? SelectedState : UnselectedState, true); })
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public static Brush ConvertNodeTypeToBrush(NodeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NodeType.Special => new SolidColorBrush(Color.FromRgb(0x9b, 0x00, 0x00)),
|
||||
NodeType.Literal => new SolidColorBrush(Color.FromRgb(0x49, 0x49, 0x49)),
|
||||
NodeType.Code => new SolidColorBrush(Color.FromRgb(0x00, 0x60, 0x0f)),
|
||||
NodeType.Group => new SolidColorBrush(Color.FromRgb(0x7B, 0x1F, 0xA2)),
|
||||
_ => throw new Exception("Unsupported node type")
|
||||
};
|
||||
}
|
||||
|
||||
#region SelectedStates
|
||||
|
||||
public const string SelectedVisualStatesGroup = "SelectedStates";
|
||||
public const string SelectedState = "Selected";
|
||||
public const string UnselectedState = "Unselected";
|
||||
|
||||
#endregion
|
||||
|
||||
#region CollapsedStates
|
||||
|
||||
public const string CollapsedVisualStatesGroup = "CollapsedStates";
|
||||
public const string CollapsedState = "Collapsed";
|
||||
public const string ExpandedState = "Expanded";
|
||||
|
||||
#endregion
|
||||
|
||||
#region ViewModel
|
||||
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(CodeGenNodeViewModel), typeof(CodeGenNodeView), new PropertyMetadata(null));
|
||||
|
||||
public CodeGenNodeViewModel? ViewModel
|
||||
{
|
||||
get => (CodeGenNodeViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object? IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (CodeGenNodeViewModel?)value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(CodeGenNodeView));
|
||||
|
||||
public CornerRadius CornerRadius
|
||||
{
|
||||
get => (CornerRadius)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ArrowSizeProperty = DependencyProperty.Register(nameof(ArrowSize), typeof(double), typeof(CodeGenNodeView));
|
||||
|
||||
public double ArrowSize
|
||||
{
|
||||
get => (double)GetValue(ArrowSizeProperty);
|
||||
set => SetValue(ArrowSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleFontFamilyProperty = DependencyProperty.Register(nameof(TitleFontFamily), typeof(FontFamily), typeof(CodeGenNodeView));
|
||||
|
||||
public FontFamily TitleFontFamily
|
||||
{
|
||||
get => (FontFamily)GetValue(TitleFontFamilyProperty);
|
||||
set => SetValue(TitleFontFamilyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register(nameof(TitleFontSize), typeof(double), typeof(CodeGenNodeView));
|
||||
|
||||
public double TitleFontSize
|
||||
{
|
||||
get => (double)GetValue(TitleFontSizeProperty);
|
||||
set => SetValue(TitleFontSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndpointsStackingOrientationProperty = DependencyProperty.Register(nameof(EndpointsStackingOrientation), typeof(Orientation), typeof(CodeGenNodeView));
|
||||
|
||||
public Orientation EndpointsStackingOrientation
|
||||
{
|
||||
get => (Orientation)GetValue(EndpointsStackingOrientationProperty);
|
||||
set => SetValue(EndpointsStackingOrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TrailingControlPresenterStyleProperty = DependencyProperty.Register(nameof(TrailingControlPresenterStyle), typeof(Style), typeof(CodeGenNodeView));
|
||||
|
||||
public Style TrailingControlPresenterStyle
|
||||
{
|
||||
get => (Style)GetValue(TrailingControlPresenterStyleProperty);
|
||||
set => SetValue(TrailingControlPresenterStyleProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user