port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
<UserControl x:Class="Intromat.Views.CodeGenConnectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:NodeNetwork.Views;assembly=NodeNetwork"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<views:ConnectionView x:Name="ConnectionView" />
</UserControl>

View File

@@ -0,0 +1,36 @@
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
public partial class CodeGenConnectionView : IViewFor<CodeGenConnectionViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(CodeGenConnectionViewModel), typeof(CodeGenConnectionView), new PropertyMetadata(null));
public CodeGenConnectionView()
{
InitializeComponent();
this.WhenActivated(d =>
{
ConnectionView.ViewModel = ViewModel;
d(Disposable.Create(() => ConnectionView.ViewModel = null));
});
}
public CodeGenConnectionViewModel? ViewModel
{
get => (CodeGenConnectionViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodeGenConnectionViewModel?)value;
}
}
}

View File

@@ -0,0 +1,41 @@
<UserControl x:Class="Intromat.Views.CodeGenNetworkView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Intromat.Views"
xmlns:views="clr-namespace:NodeNetwork.Views;assembly=NodeNetwork"
xmlns:converters="clr-namespace:Intromat.Views.Converters"
xmlns:nodes="clr-namespace:Intromat.ViewModels.Nodes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:TypeVisibilityCheck x:Key="TypeCheckToVisibility" />
<ContextMenu x:Key="nodeMenu" x:Shared="True">
<MenuItem x:Name="_groupNodesButton" Header="Group nodes" />
<MenuItem x:Name="_ungroupNodesButton" Header="Ungroup nodes"
Visibility="{Binding Converter={StaticResource TypeCheckToVisibility}, ConverterParameter={x:Type nodes:GroupNodeViewModel}}" />
<MenuItem x:Name="_openGroupButton" Header="Open group"
Visibility="{Binding Converter={StaticResource TypeCheckToVisibility}, ConverterParameter={x:Type nodes:GroupNodeViewModel}}" />
</ContextMenu>
</UserControl.Resources>
<views:NetworkView x:Name="_network">
<views:NetworkView.Resources>
<Style TargetType="local:CodeGenNodeView" BasedOn="{StaticResource {x:Type local:CodeGenNodeView}}">
<Setter Property="ContextMenu" Value="{StaticResource nodeMenu}" />
</Style>
</views:NetworkView.Resources>
<views:NetworkView.NetworkBackground>
<DrawingBrush TileMode="Tile" Viewport="0,0,96,96" ViewportUnits="Absolute" Viewbox="0,0,96,96"
ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<Geometry>M 77.000,37.000 L 59.000,37.000 L 59.000,19.000 L 77.000,19.000 L 77.000,37.000 Z M 77.000,57.000 L 59.000,57.000 L 59.000,38.000 L 77.000,38.000 L 77.000,57.000 Z M 77.000,76.000 L 59.000,76.000 L 59.000,58.000 L 77.000,58.000 L 77.000,76.000 Z M 77.000,94.000 L 59.000,94.000 L 59.000,77.000 L 77.000,77.000 L 77.000,94.000 Z M 39.000,94.000 L 39.000,77.000 L 58.000,77.000 L 58.000,94.000 L 39.000,94.000 Z M 20.000,94.000 L 20.000,77.000 L 38.000,77.000 L 38.000,94.000 L 20.000,94.000 Z M 2.000,94.000 L 2.000,77.000 L 19.000,77.000 L 19.000,94.000 L 2.000,94.000 Z M 2.000,58.000 L 19.000,58.000 L 19.000,76.000 L 2.000,76.000 L 2.000,58.000 Z M 2.000,38.000 L 19.000,38.000 L 19.000,57.000 L 2.000,57.000 L 2.000,38.000 Z M 2.000,19.000 L 19.000,19.000 L 19.000,37.000 L 2.000,37.000 L 2.000,19.000 Z M 38.000,19.000 L 38.000,37.000 L 20.000,37.000 L 20.000,19.000 L 38.000,19.000 Z M 39.000,57.000 L 39.000,38.000 L 58.000,38.000 L 58.000,57.000 L 39.000,57.000 Z M 39.000,58.000 L 58.000,58.000 L 58.000,76.000 L 39.000,76.000 L 39.000,58.000 Z M 20.000,57.000 L 20.000,38.000 L 38.000,38.000 L 38.000,57.000 L 20.000,57.000 Z M 38.000,58.000 L 38.000,76.000 L 20.000,76.000 L 20.000,58.000 L 38.000,58.000 Z M 58.000,19.000 L 58.000,37.000 L 39.000,37.000 L 39.000,19.000 L 58.000,19.000 Z M 96.000,19.000 L 96.000,18.000 L 78.000,18.000 L 78.000,0.000 L 77.000,0.000 L 77.000,18.000 L 59.000,18.000 L 59.000,0.000 L 58.000,0.000 L 58.000,18.000 L 39.000,18.000 L 39.000,0.000 L 38.000,0.000 L 38.000,18.000 L 20.000,18.000 L 20.000,0.000 L 19.000,0.000 L 19.000,18.000 L 2.000,18.000 L 2.000,0.000 L 0.000,0.000 L 0.000,18.000 L 0.000,19.000 L 0.000,37.000 L 0.000,38.000 L 0.000,57.000 L 0.000,58.000 L 0.000,76.000 L 0.000,77.000 L 0.000,94.000 L 0.000,96.000 L 2.000,96.000 L 19.000,96.000 L 20.000,96.000 L 38.000,96.000 L 39.000,96.000 L 58.000,96.000 L 59.000,96.000 L 77.000,96.000 L 78.000,96.000 L 96.000,96.000 L 96.000,94.000 L 78.000,94.000 L 78.000,77.000 L 96.000,77.000 L 96.000,76.000 L 78.000,76.000 L 78.000,58.000 L 96.000,58.000 L 96.000,57.000 L 78.000,57.000 L 78.000,38.000 L 96.000,38.000 L 96.000,37.000 L 78.000,37.000 L 78.000,19.000 L 96.000,19.000 Z</Geometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</views:NetworkView.NetworkBackground>
</views:NetworkView>
</UserControl>

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels;
using NodeNetwork.ViewModels;
using NodeNetwork.Views;
using ReactiveUI;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for CodeGenNetworkView.xaml
/// </summary>
public partial class CodeGenNetworkView : IViewFor<CodeGenNetworkViewModel>
{
private readonly MenuItem _groupNodesButton;
private readonly MenuItem _openGroupButton;
private readonly MenuItem _ungroupNodesButton;
public CodeGenNetworkView()
{
InitializeComponent();
var nodeMenu = ((ContextMenu)Resources["nodeMenu"]).Items.OfType<MenuItem>().ToList();
_groupNodesButton = nodeMenu.First(c => c.Name == nameof(_groupNodesButton));
_ungroupNodesButton = nodeMenu.First(c => c.Name == nameof(_ungroupNodesButton));
_openGroupButton = nodeMenu.First(c => c.Name == nameof(_openGroupButton));
this.WhenActivated(d =>
{
Observable.FromEventPattern<NetworkView.NodeMoveStartDelegate, NetworkView.NodeMoveStartEventArgs>(handler => _network.NodeMoveStart += handler, handler => _network.NodeMoveStart -= handler)
.Select(e => e.EventArgs.Nodes.ToDictionary(node => node, node => node.Position))
.Zip(Observable.FromEventPattern<NetworkView.NodeMoveEndDelegate, NetworkView.NodeMoveEndEventArgs>(handler => _network.NodeMoveEnd += handler, handler => _network.NodeMoveEnd -= handler))
.Select(pair => pair.Second.EventArgs.Nodes.ToDictionary(node => node, node => (pair.First[node], node.Position)))
.Subscribe(RecordNodeDragAction)
.DisposeWith(d);
var networkViewModel = ViewModel!;
_network.ViewModel = networkViewModel;
this.BindCommand(networkViewModel, vm => vm.GroupNodes, v => v._groupNodesButton).DisposeWith(d);
this.BindCommand(networkViewModel, vm => vm.UngroupNodes, v => v._ungroupNodesButton).DisposeWith(d);
this.BindCommand(networkViewModel, vm => vm.OpenGroup, v => v._openGroupButton).DisposeWith(d);
});
}
private void RecordNodeDragAction(IDictionary<NodeViewModel, (Point, Point)> nodePositions)
{
var undoRedo = ViewModel!.Document.MainViewModel.UndoRedo;
undoRedo.PushGroup(ViewModel.Document);
foreach (var (node, (before, after)) in nodePositions)
undoRedo.Record(new UndoItem<NodeViewModel, Point>(ViewModel.Document, node, v => v.Position, before, after));
undoRedo.PopGroup();
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodeGenNetworkViewModel?)value;
}
public CodeGenNetworkViewModel? ViewModel { get; set; }
}
}

View 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
}
}

View File

@@ -0,0 +1,10 @@
<UserControl x:Class="Intromat.Views.CodeGenPendingConnectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:NodeNetwork.Views;assembly=NodeNetwork"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<views:PendingConnectionView x:Name="PendingConnectionView" />
</UserControl>

View File

@@ -0,0 +1,36 @@
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
public partial class CodeGenPendingConnectionView : IViewFor<CodeGenPendingConnectionViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(CodeGenPendingConnectionViewModel), typeof(CodeGenPendingConnectionView), new PropertyMetadata(null));
public CodeGenPendingConnectionView()
{
InitializeComponent();
this.WhenActivated(d =>
{
PendingConnectionView.ViewModel = ViewModel;
d(Disposable.Create(() => PendingConnectionView.ViewModel = null));
});
}
public CodeGenPendingConnectionViewModel? ViewModel
{
get => (CodeGenPendingConnectionViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodeGenPendingConnectionViewModel?)value;
}
}
}

View File

@@ -0,0 +1,76 @@
<UserControl x:Class="Intromat.Views.CodeGenPortView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:NodeNetwork.Views;assembly=NodeNetwork"
xmlns:local1="clr-namespace:Intromat.Views"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="100">
<UserControl.Resources>
<!-- ReSharper disable Xaml.RedundantResource -->
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.ExecutionPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Path Fill="White" Data="M 0 0 L 8 0 L 18 10 L 8 20 L 0 20 Z" HorizontalAlignment="Center"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.IntegerPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Ellipse Fill="#7cb342" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#7cb342" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.FloatPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Ellipse Fill="#68c8ba" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#68c8ba" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.StringPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Ellipse Fill="#ba68c8" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#ba68c8" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.BooleanPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Path Fill="#808080" Data="M 0 0 L 15 0 L 15 15 L 0 15 Z" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#808080" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.TexturePortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Ellipse Fill="#F0A040" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#F0A040" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local1:CodeGenPortView.MeshPortTemplateKey}" TargetType="views:PortView">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Width="20" Height="20">
<Ellipse Fill="#40A0F0" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15"/>
<Path Fill="#40A0F0" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4"/>
</Grid>
</Viewbox>
</ControlTemplate>
<!-- ReSharper enable Xaml.RedundantResource -->
</UserControl.Resources>
<views:PortView x:Name="PortView" RenderTransformOrigin="0.5,0.5" />
</UserControl>

View File

@@ -0,0 +1,68 @@
using System;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
public partial class CodeGenPortView : IViewFor<CodeGenPortViewModel>
{
public const string ExecutionPortTemplateKey = "ExecutionPortTemplate";
public const string IntegerPortTemplateKey = "IntegerPortTemplate";
public const string StringPortTemplateKey = "StringPortTemplate";
public const string BooleanPortTemplateKey = "BooleanPortTemplate";
public const string FloatPortTemplateKey = "FloatPortTemplate";
public const string TexturePortTemplateKey = "TexturePortTemplate";
public const string MeshPortTemplateKey = "MeshPortTemplate";
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(CodeGenPortViewModel), typeof(CodeGenPortView), new PropertyMetadata(null));
public CodeGenPortView()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.WhenAnyValue(v => v.ViewModel)
.BindTo(this, v => v.PortView.ViewModel)
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.PortType, v => v.PortView.Template, GetTemplateFromPortType)
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.IsMirrored, v => v.PortView.RenderTransform, isMirrored => new ScaleTransform(isMirrored ? -1.0 : 1.0, 1.0))
.DisposeWith(d);
});
}
public CodeGenPortViewModel? ViewModel
{
get => (CodeGenPortViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodeGenPortViewModel?)value;
}
public ControlTemplate GetTemplateFromPortType(EPortType type)
{
return type switch
{
EPortType.Execution => (ControlTemplate)Resources[ExecutionPortTemplateKey],
EPortType.Integer => (ControlTemplate)Resources[IntegerPortTemplateKey],
EPortType.String => (ControlTemplate)Resources[StringPortTemplateKey],
EPortType.Boolean => (ControlTemplate)Resources[BooleanPortTemplateKey],
EPortType.Float => (ControlTemplate)Resources[FloatPortTemplateKey],
EPortType.Texture => (ControlTemplate)Resources[TexturePortTemplateKey],
EPortType.Mesh => (ControlTemplate)Resources[MeshPortTemplateKey],
_ => throw new Exception("Unsupported port type")
};
}
}
}

View File

@@ -0,0 +1,26 @@
<UserControl x:Class="Intromat.Views.CodePreviewView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Content="Code" HorizontalAlignment="Left" Margin="10,10,0,10" VerticalAlignment="Top" FontSize="18"
FontFamily="Segoe UI Semilight" />
<Grid Grid.Row="1" Margin="10,0,10,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock x:Name="errorTextBlock" Foreground="Red" HorizontalAlignment="Left" VerticalAlignment="Top"
TextWrapping="Wrap" />
</Grid>
<Grid Grid.Row="2" Margin="10,0,10,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock x:Name="codeTextBlock" HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,36 @@
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
public partial class CodePreviewView : IViewFor<CodePreviewViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(CodePreviewViewModel), typeof(CodePreviewView), new PropertyMetadata(null));
public CodePreviewView()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.CompiledCode, v => v.codeTextBlock.Text).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.CompilerError, v => v.errorTextBlock.Text).DisposeWith(d);
});
}
public CodePreviewViewModel? ViewModel
{
get => (CodePreviewViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodePreviewViewModel?)value;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Intromat.Views.Converters
{
/// <summary>
/// Given an object o and a type t, return Visible if o is of type t, else return Collapsed.
/// </summary>
public class TypeVisibilityCheck : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((Type)parameter).IsInstanceOfType(value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,18 @@
<UserControl x:Class="Intromat.Views.DocumentView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:breadcrumbBar="clr-namespace:NodeNetwork.Toolkit.BreadcrumbBar;assembly=NodeNetworkToolkit"
xmlns:reactiveUi="http://reactiveui.net"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<breadcrumbBar:BreadcrumbBarView Grid.Row="0" x:Name="_breadcrumbBar" Margin="-2,-2,-1,-1" />
<reactiveUi:ViewModelViewHost Grid.Row="1" x:Name="_content" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels;
using NodeNetwork.ViewModels;
using NodeNetwork.Views;
using ReactiveUI;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for DocumentView.xaml
/// </summary>
public partial class DocumentView : IViewFor<DocumentViewModel>
{
public DocumentView()
{
InitializeComponent();
this.WhenActivated(d =>
{
var documentViewModel = ViewModel!;
this.OneWayBind(documentViewModel, vm => vm.CurrentViewModel, v => v._content.ViewModel).DisposeWith(d);
this.OneWayBind(documentViewModel, vm => vm.NetworkBreadcrumbBar, v => v._breadcrumbBar.ViewModel).DisposeWith(d);
});
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (DocumentViewModel?)value;
}
public DocumentViewModel? ViewModel { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
<Grid x:Class="Intromat.Views.DxView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas MinWidth="64" MinHeight="64">
<Image x:Name="_swapChainImage" Opacity="1.0" />
</Canvas>
</Grid>

View File

@@ -0,0 +1,314 @@
using System;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
using Intromat.Graphics;
using SharpDX.DXGI;
using Splat;
using D3D9 = SharpDX.Direct3D9;
using D3D11 = SharpDX.Direct3D11;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for DxView.xaml
/// </summary>
public partial class DxView
{
private readonly D3DImage _d3dImage;
private readonly DxHost _dxHost;
private int _backBufferHeight = -1;
private bool _backBufferMultiSample;
private D3D11.Texture2D? _backBufferTexture;
private D3D11.RenderTargetView? _backBufferView;
private int _backBufferWidth = -1;
private D3D9.Surface? _d3d9Surface;
private D3D9.Texture? _d3d9Texture;
private D3D11.Texture2D? _depthBufferTexture;
private D3D11.DepthStencilView? _depthBufferView;
private TimeSpan _lastRender;
private volatile IntPtr _nextFrame = IntPtr.Zero;
private bool _supportRemoteDesktop;
private D3D11.Texture2D? _transferBuffer;
private D3D11.Texture2D? _transferBuffer2;
private D3D11.Query? _transferCompleteQuery;
private DxHost.RenderDelegate? _updateHandler;
public DxView()
{
InitializeComponent();
_dxHost = Locator.Current.GetService<DxHost>()!;
_d3dImage = new D3DImage();
_swapChainImage.Source = _d3dImage;
SizeChanged += HostSizeChanged;
Loaded += OnLoaded;
Unloaded += OnUnloaded;
Dispatcher.ShutdownStarted += OnUnloaded;
}
public int ViewHeight { get; private set; }
public int ViewWidth { get; private set; }
private void OnLoaded(object? sender, RoutedEventArgs e)
{
CompositionTarget.Rendering += CompositionTargetRendering;
CheckHostSize();
}
private void OnUnloaded(object? sender, EventArgs e)
{
CompositionTarget.Rendering -= CompositionTargetRendering;
}
public void SetUpdateHandler(DxHost.RenderDelegate? handler)
{
_updateHandler = handler;
}
private void CompositionTargetRendering(object? sender, EventArgs e)
{
lock (this)
{
var args = (RenderingEventArgs)e;
if (_lastRender == args.RenderingTime)
return;
_lastRender = args.RenderingTime;
var nextFrame = _nextFrame;
if (nextFrame != IntPtr.Zero)
{
_nextFrame = IntPtr.Zero;
var image = _d3dImage;
var hasFrontBuffer = image.IsFrontBufferAvailable;
if (_supportRemoteDesktop || hasFrontBuffer)
{
image.Lock();
image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, nextFrame, _supportRemoteDesktop);
var targetWidth = image.PixelWidth;
var targetHeight = image.PixelHeight;
image.AddDirtyRect(new Int32Rect(0, 0, targetWidth, targetHeight));
image.Unlock();
if (hasFrontBuffer)
_supportRemoteDesktop = false;
}
else
{
_supportRemoteDesktop = SystemInformation.TerminalServerSession;
}
}
}
}
public void Render()
{
_dxHost.EnqueueAction(Render);
}
public void Render(D3D11.Device device, D3D11.DeviceContext context)
{
lock (this)
{
EnsureBuffers();
if (_backBufferTexture == null || _transferBuffer == null || _updateHandler == null)
return;
context.OutputMerger.SetTargets(_depthBufferView, _backBufferView);
context.Rasterizer.SetViewport(0, 0, ViewWidth, ViewHeight);
try
{
_updateHandler(device, context);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (_backBufferMultiSample)
{
context.ResolveSubresource(_backBufferTexture, 0, _transferBuffer2, 0, Format.B8G8R8A8_UNorm_SRgb);
context.CopyResource(_transferBuffer2, _transferBuffer);
}
else
{
context.CopyResource(_backBufferTexture, _transferBuffer);
}
context.End(_transferCompleteQuery);
while (!context.GetData(_transferCompleteQuery, out int completed) || completed == 0)
Thread.Yield();
_nextFrame = _d3d9Surface!.NativePointer;
}
}
private void HostSizeChanged(object sender, SizeChangedEventArgs e)
{
CheckHostSize();
}
private void CheckHostSize()
{
lock (this)
{
double scaleX = 1.0f;
double scaleY = 1.0f;
if (PresentationSource.FromVisual(this)?.CompositionTarget is HwndTarget hwndTarget)
{
scaleX = hwndTarget.TransformToDevice.M11;
scaleY = hwndTarget.TransformToDevice.M22;
}
var width = (int)Math.Ceiling(ActualWidth);
var height = (int)Math.Ceiling(ActualHeight);
width = width > 1 ? width : 1;
height = height > 1 ? height : 1;
if (ViewWidth == width && ViewHeight == height)
return;
ViewWidth = width;
ViewHeight = height;
Render();
}
}
private void EnsureBuffers()
{
lock (this)
{
if (_backBufferHeight != ViewHeight || _backBufferWidth != ViewWidth)
{
_backBufferHeight = ViewHeight;
_backBufferWidth = ViewWidth;
if (_d3d9Surface != null)
{
_d3d9Surface.Dispose();
_d3d9Surface = null;
}
if (_d3d9Texture != null)
{
_d3d9Texture.Dispose();
_d3d9Texture = null;
}
if (_transferBuffer != null)
{
_transferBuffer.Dispose();
_transferBuffer = null;
}
if (_transferBuffer2 != null)
{
_transferBuffer2.Dispose();
_transferBuffer2 = null;
}
if (_backBufferTexture != null) // TODO: test
{
_backBufferTexture.Dispose();
_backBufferTexture = null;
}
if (_backBufferView != null)
{
_backBufferView.Dispose();
_backBufferView = null;
}
if (_depthBufferTexture != null) // TODO: test
{
_depthBufferTexture.Dispose();
_depthBufferTexture = null;
}
if (_depthBufferView != null)
{
_depthBufferView.Dispose();
_depthBufferView = null;
}
if (_transferCompleteQuery != null)
{
_transferCompleteQuery.Dispose();
_transferCompleteQuery = null;
}
}
if (_transferBuffer == null && _dxHost.D3D9Device != null)
{
var device = _dxHost.Device;
var textureDesc = new D3D11.Texture2DDescription
{
ArraySize = 1,
MipLevels = 1,
Width = _backBufferWidth,
Height = _backBufferHeight,
SampleDescription = new SampleDescription(1, 0), // TAM
Usage = D3D11.ResourceUsage.Default,
CpuAccessFlags = D3D11.CpuAccessFlags.None,
OptionFlags = D3D11.ResourceOptionFlags.Shared,
BindFlags = D3D11.BindFlags.RenderTarget | D3D11.BindFlags.ShaderResource,
Format = Format.B8G8R8A8_UNorm
};
_transferBuffer = new D3D11.Texture2D(device, textureDesc);
textureDesc.Format = Format.B8G8R8A8_UNorm_SRgb;
textureDesc.OptionFlags = D3D11.ResourceOptionFlags.None;
_transferBuffer2 = new D3D11.Texture2D(device, textureDesc);
_backBufferMultiSample = true;
textureDesc.SampleDescription = new SampleDescription(4, 0);
textureDesc.BindFlags = D3D11.BindFlags.RenderTarget;
_backBufferTexture = new D3D11.Texture2D(device, textureDesc);
_backBufferView = new D3D11.RenderTargetView(device, _backBufferTexture);
textureDesc.Format = Format.R32_Typeless;
textureDesc.BindFlags = D3D11.BindFlags.DepthStencil;
textureDesc.OptionFlags = D3D11.ResourceOptionFlags.None;
var depthDesc = new D3D11.DepthStencilViewDescription
{
Format = Format.D32_Float,
Flags = D3D11.DepthStencilViewFlags.None,
Dimension = D3D11.DepthStencilViewDimension.Texture2DMultisampled,
Texture2DMS = new D3D11.DepthStencilViewDescription.Texture2DMultisampledResource()
};
_depthBufferTexture = new D3D11.Texture2D(device, textureDesc);
_depthBufferView = new D3D11.DepthStencilView(device, _depthBufferTexture, depthDesc);
var dxgiRes = _transferBuffer.QueryInterface<Resource>();
var handle = dxgiRes.SharedHandle;
_d3d9Texture = new D3D9.Texture(_dxHost.D3D9Device, _backBufferWidth, _backBufferHeight, 1, D3D9.Usage.RenderTarget, D3D9.Format.A8R8G8B8, D3D9.Pool.Default, ref handle);
_d3d9Surface = _d3d9Texture.GetSurfaceLevel(0);
var queryDesc = new D3D11.QueryDescription { Type = D3D11.QueryType.Event };
_transferCompleteQuery = new D3D11.Query(device, queryDesc);
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_checkBoxValue), Type = typeof(CheckBox))]
[TemplatePart(Name = nameof(_textBlockValue), Type = typeof(TextBlock))]
public class BooleanExpressionEditorView : EditorViewBase<BooleanExpressionEditorViewModel>
{
private CheckBox _checkBoxValue = null!;
private TextBlock _textBlockValue = null!;
public BooleanExpressionEditorView()
{
DefaultStyleKey = typeof(BooleanExpressionEditorView);
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.CustomValue, v => v._textBlockValue.Text, b => b.ToString()).DisposeWith(d);
this.Bind(ViewModel, vm => vm.CustomValue, v => v._checkBoxValue.IsChecked).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_checkBoxValue = (CheckBox)GetTemplateChild(nameof(_checkBoxValue))!;
_textBlockValue = (TextBlock)GetTemplateChild(nameof(_textBlockValue))!;
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_checkBoxValue), Type = typeof(CheckBox))]
[TemplatePart(Name = nameof(_textBlockValue), Type = typeof(TextBlock))]
public class BooleanValueEditorView : EditorViewBase<BooleanValueEditorViewModel>
{
private CheckBox _checkBoxValue = null!;
private TextBlock _textBlockValue = null!;
public BooleanValueEditorView()
{
DefaultStyleKey = typeof(BooleanValueEditorView);
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.Value, v => v._textBlockValue.Text, b => b.ToString()).DisposeWith(d);
this.Bind(ViewModel, vm => vm.Value, v => v._checkBoxValue.IsChecked).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_checkBoxValue = (CheckBox)GetTemplateChild(nameof(_checkBoxValue))!;
_textBlockValue = (TextBlock)GetTemplateChild(nameof(_textBlockValue))!;
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.Nodes.Code;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_sliderValue), Type = typeof(Slider))]
[TemplatePart(Name = nameof(_textBlockValue), Type = typeof(TextBlock))]
public class DimensionEditorView : EditorViewBase<DimensionEditorViewModel>
{
private Slider _sliderValue = null!;
private TextBlock _textBlockValue = null!;
public DimensionEditorView()
{
DefaultStyleKey = typeof(DimensionEditorView);
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.Value, v => v._textBlockValue.Text, v => ((IntLiteralValue?)v)?.EvaluateDimension().ToString() ?? "0").DisposeWith(d);
this.Bind(ViewModel, vm => vm.CustomValue, v => v._sliderValue.Value, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MinValue, v => v._sliderValue.Minimum, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MaxValue, v => v._sliderValue.Maximum, i => i, v => (int)v).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_sliderValue = (Slider)GetTemplateChild(nameof(_sliderValue))!;
_textBlockValue = (TextBlock)GetTemplateChild(nameof(_textBlockValue))!;
}
}
}

View File

@@ -0,0 +1,59 @@
<UserControl x:Class="Intromat.Views.Editors.EditorHeader"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="800">
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="_textBlockName" Foreground="{DynamicResource ControlDefaultForeground}" HorizontalAlignment="Stretch" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
<ComboBox Grid.Column="1" x:Name="_comboBoxRelativeSource" VerticalAlignment="Center" />
<ToggleButton Grid.Column="2" x:Name="_checkBoxPortVisible" VerticalAlignment="Center">
<Viewbox StretchDirection="Both" Stretch="Uniform" Width="16" Height="16">
<Grid Width="20" Height="20">
<Ellipse x:Name="_ellipse" HorizontalAlignment="Left" VerticalAlignment="Center" Height="15" Width="15">
<Ellipse.Fill>
<SolidColorBrush Color="#505050" />
</Ellipse.Fill>
</Ellipse>
<Path x:Name="_path" Data="M 0 0 L 4 4 L 0 8 Z" HorizontalAlignment="Right" VerticalAlignment="Center" Height="8" Width="4">
<Path.Fill>
<SolidColorBrush Color="#505050" />
</Path.Fill>
</Path>
</Grid>
</Viewbox>
<ToggleButton.Triggers>
<EventTrigger RoutedEvent="ToggleButton.Checked">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="_ellipse"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
Duration="0:0:0.2" From="#505050" To="White" />
<ColorAnimation Storyboard.TargetName="_path"
Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)"
Duration="0:0:0.2" From="#505050" To="White" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="_ellipse"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
Duration="0:0:0.2" From="White" To="#505050" />
<ColorAnimation Storyboard.TargetName="_path"
Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)"
Duration="0:0:0.2" From="White" To="#505050" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToggleButton.Triggers>
</ToggleButton>
</Grid>
</UserControl>

View File

@@ -0,0 +1,16 @@
using System.Windows;
using System.Windows.Controls;
namespace Intromat.Views.Editors
{
/// <summary>
/// Interaction logic for EditorHeader.xaml
/// </summary>
public partial class EditorHeader : UserControl
{
public EditorHeader()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.VisualStyles;
using Intromat.Interfaces;
using Intromat.Nodes.Code;
using Intromat.ViewModels;
using NodeNetwork.ViewModels;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_header), Type = typeof(EditorHeader))]
[TemplatePart(Name = nameof(_content), Type = typeof(Panel))]
public abstract class EditorViewBase<T> : ContentControl, IViewFor<T> where T : NodeEndpointEditorViewModel
{
protected EditorHeader _header = null!;
protected Panel _content = null!;
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(T), typeof(EditorViewBase<T>), new PropertyMetadata(null));
protected EditorViewBase()
{
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.Parent.Name, v => v._header._textBlockName.Text)
.DisposeWith(d);
if (ViewModel is IExpressionEditor expressionEditor)
{
if (expressionEditor.HasParentSource)
_header._comboBoxRelativeSource.Items.Add(ERelativeSource.Parent);
if (expressionEditor.HasInputSource)
_header._comboBoxRelativeSource.Items.Add(ERelativeSource.Input);
if (_header._comboBoxRelativeSource.Items.Count > 0)
_header._comboBoxRelativeSource.Items.Add(ERelativeSource.Custom);
else
_header._comboBoxRelativeSource.Visibility = Visibility.Collapsed;
this.Bind(expressionEditor, vm => vm.RelativeSource, v => v._header._comboBoxRelativeSource.SelectedItem)
.DisposeWith(d);
if (expressionEditor.CodeGenPort.PortType == EPortType.None)
{
_header._checkBoxPortVisible.Visibility = Visibility.Collapsed;
}
else
{
this.Bind(expressionEditor, vm => vm.CodeGenPort.IsPortVisible, v => v._header._checkBoxPortVisible.IsChecked)
.DisposeWith(d);
this.OneWayBind(expressionEditor, vm => vm.CodeGenPort.IsPortVisible, v => v._content.Visibility, portVisible => portVisible ? Visibility.Collapsed : Visibility.Visible)
.DisposeWith(d);
}
}
else
{
_header._comboBoxRelativeSource.Visibility = Visibility.Collapsed;
}
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_header = (EditorHeader)GetTemplateChild(nameof(_header))!;
_content = (Panel)GetTemplateChild(nameof(_content))!;
}
public T? ViewModel
{
get => (T?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (T?)value;
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_comboBoxValue), Type = typeof(ComboBox))]
public class EnumEditorView : EditorViewBase<EnumEditorViewModel>
{
private ComboBox _comboBoxValue = null!;
public EnumEditorView()
{
DefaultStyleKey = typeof(EnumEditorView);
this.WhenActivated(d =>
{
foreach (var name in Enum.GetNames(ViewModel!.EnumType))
_comboBoxValue.Items.Add(name);
this.OneWayBind(ViewModel, vm => vm.Value, v => v._comboBoxValue.SelectedIndex).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_comboBoxValue = (ComboBox)GetTemplateChild(nameof(_comboBoxValue))!;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_sliderValue), Type = typeof(Slider))]
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class FloatExpressionEditorView : EditorViewBase<FloatExpressionEditorViewModel>
{
private Slider _sliderValue = null!;
private TextBox _textBoxValue = null!;
public FloatExpressionEditorView()
{
DefaultStyleKey = typeof(FloatExpressionEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.CustomValue, v => v._textBoxValue.Text).DisposeWith(d);
this.Bind(ViewModel, vm => vm.CustomValue, v => v._sliderValue.Value, i => i, v => (float)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MinValue, v => v._sliderValue.Minimum, i => i, v => (float)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MaxValue, v => v._sliderValue.Maximum, i => i, v => (float)v).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_sliderValue = (Slider)GetTemplateChild(nameof(_sliderValue))!;
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_sliderValue), Type = typeof(Slider))]
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class FloatValueEditorView : EditorViewBase<FloatValueEditorViewModel>
{
private Slider _sliderValue = null!;
private TextBox _textBoxValue = null!;
public FloatValueEditorView()
{
DefaultStyleKey = typeof(FloatValueEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.Value, v => v._textBoxValue.Text).DisposeWith(d);
this.Bind(ViewModel, vm => vm.Value, v => v._sliderValue.Value, i => i, v => (float)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MinValue, v => v._sliderValue.Minimum, i => i, v => (float)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MaxValue, v => v._sliderValue.Maximum, i => i, v => (float)v).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_sliderValue = (Slider)GetTemplateChild(nameof(_sliderValue))!;
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="Intromat.Views.Editors.GroupEndpointEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="800">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="nameTextBox" Width="125" />
<ToggleButton x:Name="editNameButton" Margin="5,0,0,0">Edit name</ToggleButton>
<Button x:Name="upButton" Margin="5,0,0,0">▲</Button>
<Button x:Name="downButton" Margin="5,0,0,0">▼</Button>
<Button x:Name="deleteButton" Margin="5,0,0,0">Delete</Button>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,45 @@
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using Intromat.ViewModels.Nodes;
using ReactiveUI;
namespace Intromat.Views.Editors
{
public partial class GroupEndpointEditorView : IViewFor<IGroupEndpointEditorViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(IGroupEndpointEditorViewModel), typeof(GroupEndpointEditorView), new PropertyMetadata(null));
public GroupEndpointEditorView()
{
InitializeComponent();
this.WhenAnyValue(v => v.editNameButton.IsChecked)
.Select(isChecked => isChecked ?? false ? Visibility.Visible : Visibility.Collapsed)
.BindTo(this, v => v.nameTextBox.Visibility);
this.WhenActivated(d =>
{
Debug.Assert(ViewModel != null, nameof(ViewModel) + " != null");
this.Bind(ViewModel, vm => vm.Endpoint.Name, v => v.nameTextBox.Text).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.MoveUp, v => v.upButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.MoveDown, v => v.downButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.Delete, v => v.deleteButton).DisposeWith(d);
});
}
public IGroupEndpointEditorViewModel? ViewModel
{
get => (IGroupEndpointEditorViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IGroupEndpointEditorViewModel?)value;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_sliderValue), Type = typeof(Slider))]
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class IntegerExpressionEditorView : EditorViewBase<IntegerExpressionEditorViewModel>
{
private Slider _sliderValue = null!;
private TextBox _textBoxValue = null!;
public IntegerExpressionEditorView()
{
DefaultStyleKey = typeof(IntegerExpressionEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.CustomValue, v => v._textBoxValue.Text).DisposeWith(d);
this.Bind(ViewModel, vm => vm.CustomValue, v => v._sliderValue.Value, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MinValue, v => v._sliderValue.Minimum, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MaxValue, v => v._sliderValue.Maximum, i => i, v => (int)v).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_sliderValue = (Slider)GetTemplateChild(nameof(_sliderValue))!;
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_sliderValue), Type = typeof(Slider))]
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class IntegerValueEditorView : EditorViewBase<IntegerValueEditorViewModel>
{
private Slider _sliderValue = null!;
private TextBox _textBoxValue = null!;
public IntegerValueEditorView()
{
DefaultStyleKey = typeof(IntegerValueEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.Value, v => v._textBoxValue.Text).DisposeWith(d);
this.Bind(ViewModel, vm => vm.Value, v => v._sliderValue.Value, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MinValue, v => v._sliderValue.Minimum, i => i, v => (int)v).DisposeWith(d);
this.Bind(ViewModel, vm => vm.MaxValue, v => v._sliderValue.Maximum, i => i, v => (int)v).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_sliderValue = (Slider)GetTemplateChild(nameof(_sliderValue))!;
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.Interfaces;
using Intromat.ViewModels.Editors;
using ReactiveUI;
using SharpDX.Direct3D11;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_comboBoxFilter), Type = typeof(ComboBox))]
[TemplatePart(Name = nameof(_comboBoxAddress), Type = typeof(ComboBox))]
public class SamplerEditorView : EditorViewBase<SamplerEditorViewModel>
{
private ComboBox _comboBoxFilter = null!;
private ComboBox _comboBoxAddress = null!;
public SamplerEditorView()
{
DefaultStyleKey = typeof(SamplerEditorView);
this.WhenActivated(d =>
{
var addressNames = Enum.GetValues(typeof(TextureAddressMode)).Cast<TextureAddressMode>().ToArray();
_comboBoxAddress.ItemsSource = addressNames;
var filterNames = Enum.GetValues(typeof(Filter)).Cast<Filter>();
_comboBoxFilter.ItemsSource = filterNames;
this.Bind(ViewModel, vm => vm.Address, v => v._comboBoxAddress.SelectedItem).DisposeWith(d);
this.Bind(ViewModel, vm => vm.Filter, v => v._comboBoxFilter.SelectedItem).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_comboBoxFilter = (ComboBox)GetTemplateChild(nameof(_comboBoxFilter))!;
_comboBoxAddress = (ComboBox)GetTemplateChild(nameof(_comboBoxAddress))!;
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class StringExpressionEditorView : EditorViewBase<StringExpressionEditorViewModel>
{
private TextBox _textBoxValue = null!;
public StringExpressionEditorView()
{
DefaultStyleKey = typeof(StringExpressionEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.CustomValue, v => v._textBoxValue.Text).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels.Editors;
using ReactiveUI;
namespace Intromat.Views.Editors
{
[TemplatePart(Name = nameof(_textBoxValue), Type = typeof(TextBox))]
public class StringValueEditorView : EditorViewBase<StringValueEditorViewModel>
{
private TextBox _textBoxValue = null!;
public StringValueEditorView()
{
DefaultStyleKey = typeof(StringValueEditorView);
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.Value, v => v._textBoxValue.Text).DisposeWith(d);
});
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBoxValue = (TextBox)GetTemplateChild(nameof(_textBoxValue))!;
}
}
}

View File

@@ -0,0 +1,78 @@
<UserControl x:Class="Intromat.Views.ExplorerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModels="clr-namespace:Intromat.ViewModels"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance {x:Type viewModels:ExplorerViewModel}}"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style x:Key="TreeViewIcon" TargetType="Image">
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Margin" Value="2,0,5,0" />
</Style>
<ContextMenu x:Key="projectMenu" x:Shared="True">
<MenuItem x:Name="_newModuleButton" Header="New module..." Icon="{StaticResource ModuleImage}" />
</ContextMenu>
<ContextMenu x:Key="moduleMenu" x:Shared="True">
<MenuItem x:Name="_renameModuleButton" Header="Rename module..." Icon="{StaticResource RenameImage}" />
<MenuItem x:Name="_deleteModuleButton" Header="Delete module" Icon="{StaticResource DeleteImage}" />
<MenuItem x:Name="_createModuleFolderButton" Header="Create folder..." Icon="{StaticResource FolderOpenImage}" />
<MenuItem x:Name="_createModuleFileButton" Header="Create file..." Icon="{StaticResource GraphImage}" />
</ContextMenu>
<ContextMenu x:Key="folderMenu" x:Shared="True">
<MenuItem x:Name="_renameFolderButton" Header="Rename folder..." Icon="{StaticResource RenameImage}" />
<MenuItem x:Name="_deleteFolderButton" Header="Delete folder" Icon="{StaticResource DeleteImage}" />
<MenuItem x:Name="_createSubFolderButton" Header="Create folder..." Icon="{StaticResource FolderOpenImage}" />
<MenuItem x:Name="_createSubFileButton" Header="Create file..." Icon="{StaticResource GraphImage}" />
</ContextMenu>
<ContextMenu x:Key="documentMenu" x:Shared="True">
<MenuItem x:Name="_renameFileButton" Header="Rename file..." Icon="{StaticResource RenameImage}" />
<MenuItem x:Name="_deleteFileButton" Header="Delete file" Icon="{StaticResource DeleteImage}" />
</ContextMenu>
</UserControl.Resources>
<TreeView x:Name="_treeView">
<TreeView.Resources>
<Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
<HierarchicalDataTemplate DataType="{x:Type viewModels:ProjectViewModel}" ItemsSource="{Binding Modules}">
<StackPanel Orientation="Horizontal" Height="20" ContextMenu="{StaticResource projectMenu}">
<Image Style="{StaticResource TreeViewIcon}" Source="{StaticResource ProjectImageSource}" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="0,0,2,0" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type viewModels:ModuleViewModel}" ItemsSource="{Binding TreeChildren}">
<StackPanel Orientation="Horizontal" Height="20" ContextMenu="{StaticResource moduleMenu}">
<Image Style="{StaticResource TreeViewIcon}" Source="{StaticResource ModuleImageSource}" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="0,0,2,0" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type viewModels:FolderViewModel}" ItemsSource="{Binding TreeChildren}">
<StackPanel Orientation="Horizontal" Height="20" ContextMenu="{StaticResource folderMenu}">
<Image Style="{StaticResource TreeViewIcon}" Source="{StaticResource FolderClosedImageSource}" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="0,0,2,0" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type viewModels:DocumentViewModel}">
<StackPanel Orientation="Horizontal" Height="20" ContextMenu="{StaticResource documentMenu}">
<Image Style="{StaticResource TreeViewIcon}" Source="{StaticResource GraphImageSource}" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="0,0,2,0" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ShaderFileViewModel}">
<StackPanel Orientation="Horizontal" Height="20" ContextMenu="{StaticResource documentMenu}">
<Image Style="{StaticResource TreeViewIcon}" Source="{StaticResource GraphImageSource}" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="0,0,2,0" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</UserControl>

View File

@@ -0,0 +1,105 @@
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for ExplorerView.xaml
/// </summary>
public partial class ExplorerView : IViewFor<ExplorerViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ExplorerViewModel), typeof(ExplorerView), new PropertyMetadata(null));
private readonly MenuItem _newModuleButton;
private readonly MenuItem _renameModuleButton;
private readonly MenuItem _deleteModuleButton;
private readonly MenuItem _createModuleFolderButton;
private readonly MenuItem _renameFolderButton;
private readonly MenuItem _deleteFolderButton;
private readonly MenuItem _createSubFolderButton;
private readonly MenuItem _createModuleFileButton;
private readonly MenuItem _createSubFileButton;
private readonly MenuItem _renameFileButton;
private readonly MenuItem _deleteFileButton;
public ExplorerView()
{
InitializeComponent();
var projectMenu = (ContextMenu)Resources["projectMenu"];
var projectMenuItems = projectMenu.Items.OfType<MenuItem>().ToList();
_newModuleButton = projectMenuItems.First(c => c.Name == nameof(_newModuleButton));
var moduleMenu = (ContextMenu)Resources["moduleMenu"];
var moduleMenuItems = moduleMenu.Items.OfType<MenuItem>().ToList();
_renameModuleButton = moduleMenuItems.First(c => c.Name == nameof(_renameModuleButton));
_deleteModuleButton = moduleMenuItems.First(c => c.Name == nameof(_deleteModuleButton));
_createModuleFolderButton = moduleMenuItems.First(c => c.Name == nameof(_createModuleFolderButton));
_createModuleFileButton = moduleMenuItems.First(c => c.Name == nameof(_createModuleFileButton));
var folderMenu = (ContextMenu)Resources["folderMenu"];
var folderMenuItems = folderMenu.Items.OfType<MenuItem>().ToList();
_renameFolderButton = folderMenuItems.First(c => c.Name == nameof(_renameFolderButton));
_deleteFolderButton = folderMenuItems.First(c => c.Name == nameof(_deleteFolderButton));
_createSubFolderButton = folderMenuItems.First(c => c.Name == nameof(_createSubFolderButton));
_createSubFileButton = folderMenuItems.First(c => c.Name == nameof(_createSubFileButton));
var documentMenu = (ContextMenu)Resources["documentMenu"];
var documentMenuItems = documentMenu.Items.OfType<MenuItem>().ToList();
_renameFileButton = documentMenuItems.First(c => c.Name == nameof(_renameFileButton));
_deleteFileButton = documentMenuItems.First(c => c.Name == nameof(_deleteFileButton));
this.WhenActivated(d =>
{
_treeView.ItemsSource = ViewModel!.TreeRoot;
_treeView.Events().MouseDoubleClick.Subscribe(OnTreeViewDoubleClicked);
projectMenu.Events().DataContextChanged.Subscribe(args => ViewModel.CurrentProject = (ProjectViewModel)args.NewValue);
moduleMenu.Events().DataContextChanged.Subscribe(args => ViewModel.CurrentModule = (ModuleViewModel)args.NewValue);
folderMenu.Events().DataContextChanged.Subscribe(args => ViewModel.CurrentFolder = (FolderViewModel)args.NewValue);
documentMenu.Events().DataContextChanged.Subscribe(args => ViewModel.CurrentFile = (FileViewModel)args.NewValue);
this.BindCommand(ViewModel, vm => vm.NewModule, v => v._newModuleButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.RenameModule, v => v._renameModuleButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.DeleteModule, v => v._deleteModuleButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.NewModuleFolder, v => v._createModuleFolderButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.NewSubFolder, v => v._createSubFolderButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.RenameFolder, v => v._renameFolderButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.DeleteFolder, v => v._deleteFolderButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.NewFile, v => v._createModuleFileButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.NewFile, v => v._createSubFileButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.RenameFile, v => v._renameFileButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.DeleteFile, v => v._deleteFileButton).DisposeWith(d);
});
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (ExplorerViewModel?)value;
}
public ExplorerViewModel? ViewModel
{
get => (ExplorerViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
private void OnTreeViewDoubleClicked(MouseButtonEventArgs args)
{
var vm = ((FrameworkElement)args.OriginalSource).DataContext;
if (vm is FileViewModel fileVm)
{
var mainVm = ViewModel!.MainViewModel;
if (mainVm.Files.All(d => d != fileVm))
mainVm.Files.Add(fileVm);
mainVm.ActiveFile = fileVm;
}
}
}
}

View File

@@ -0,0 +1,24 @@
<UserControl x:Class="Intromat.Views.GroupNodeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:Intromat.Views"
xmlns:newEndpointDropPanel="clr-namespace:NodeNetwork.Toolkit.Group.AddEndpointDropPanel;assembly=NodeNetworkToolkit"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<views:CodeGenNodeView x:Name="NodeView">
<views:CodeGenNodeView.TrailingControlPresenterStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Content" Value="{Binding AddEndpointDropPanelVM}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<newEndpointDropPanel:AddEndpointDropPanelView ViewModel="{Binding }" Margin="0,5,0,0" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</views:CodeGenNodeView.TrailingControlPresenterStyle>
</views:CodeGenNodeView>
</UserControl>

View File

@@ -0,0 +1,38 @@
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels.Nodes;
using ReactiveUI;
namespace Intromat.Views
{
public partial class GroupNodeView : IViewFor<GroupNodeViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(GroupNodeViewModel), typeof(GroupNodeView), new PropertyMetadata(null));
public GroupNodeView()
{
InitializeComponent();
this.WhenActivated(d =>
{
NodeView.ViewModel = ViewModel;
Disposable.Create(() => NodeView.ViewModel = null).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.NodeType, v => v.NodeView.Background, CodeGenNodeView.ConvertNodeTypeToBrush).DisposeWith(d);
});
}
public GroupNodeViewModel? ViewModel
{
get => (GroupNodeViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (GroupNodeViewModel?)value;
}
}
}

View File

@@ -0,0 +1,24 @@
<UserControl x:Class="Intromat.Views.GroupSubnetIONodeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:Intromat.Views"
xmlns:addEndpointDropPanel="clr-namespace:NodeNetwork.Toolkit.Group.AddEndpointDropPanel;assembly=NodeNetworkToolkit"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<views:CodeGenNodeView x:Name="NodeView">
<views:CodeGenNodeView.TrailingControlPresenterStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Content" Value="{Binding AddEndpointDropPanelVM}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<addEndpointDropPanel:AddEndpointDropPanelView ViewModel="{Binding }" Margin="0,5,0,0" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</views:CodeGenNodeView.TrailingControlPresenterStyle>
</views:CodeGenNodeView>
</UserControl>

View File

@@ -0,0 +1,38 @@
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels.Nodes;
using ReactiveUI;
namespace Intromat.Views
{
public partial class GroupSubnetIONodeView : IViewFor<GroupSubnetIONodeViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(GroupSubnetIONodeViewModel), typeof(GroupSubnetIONodeView), new PropertyMetadata(null));
public GroupSubnetIONodeView()
{
InitializeComponent();
this.WhenActivated(d =>
{
NodeView.ViewModel = ViewModel;
Disposable.Create(() => NodeView.ViewModel = null).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.NodeType, v => v.NodeView.Background, CodeGenNodeView.ConvertNodeTypeToBrush).DisposeWith(d);
});
}
public GroupSubnetIONodeViewModel? ViewModel
{
get => (GroupSubnetIONodeViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (GroupSubnetIONodeViewModel?)value;
}
}
}

View File

@@ -0,0 +1,110 @@
<Window x:Class="Intromat.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:nodeList="clr-namespace:NodeNetwork.Toolkit.NodeList;assembly=NodeNetworkToolkit"
xmlns:views="clr-namespace:Intromat.Views"
xmlns:viewModels="clr-namespace:Intromat.ViewModels"
xmlns:reactiveUi="http://reactiveui.net"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Style="{DynamicResource CustomWindowStyle}"
Icon="{StaticResource LogoImageSource}"
Height="960" Width="1280">
<Grid Margin="0,-30,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<Menu Grid.Row="0" Margin="35,2,2,2" VerticalAlignment="Center" HorizontalAlignment="Left" WindowChrome.IsHitTestVisibleInChrome="True">
<MenuItem Header="_File">
<MenuItem Header="E_xit" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="_Preferences..." />
</MenuItem>
<MenuItem Header="_Windows">
<MenuItem x:Name="_menuExplorer" IsCheckable="True" IsChecked="{Binding IsVisible, ElementName=_explorerAnchorable, Mode=TwoWay}" Header="_Explorer" />
<MenuItem x:Name="_menuLibrary" IsCheckable="True" IsChecked="{Binding IsVisible, ElementName=_libraryAnchorable, Mode=TwoWay}" Header="_Library" />
<MenuItem x:Name="_menu3dView" IsCheckable="True" IsChecked="{Binding IsVisible, ElementName=_3dViewAnchorable, Mode=TwoWay}" Header="_3D View" />
<MenuItem x:Name="_menu2dView" IsCheckable="True" IsChecked="{Binding IsVisible, ElementName=_2dViewAnchorable, Mode=TwoWay}" Header="_2D View" />
<MenuItem x:Name="_menuParameters" IsCheckable="True" IsChecked="{Binding IsVisible, ElementName=_parametersAnchorable, Mode=TwoWay}" Header="_Parameters" />
</MenuItem>
</Menu>
<Border Grid.Row="0" Grid.Column="1" Margin="20,0,0,0" Background="{DynamicResource BackgroundColor}" HorizontalAlignment="Left" VerticalAlignment="Center">
<TextBlock Text="Intromat" Margin="8,3" />
</Border>
</Grid>
<ToolBarTray Grid.Row="1">
<ToolBar>
<Button Name="_openButton" Style="{StaticResource IconToolButton}" ToolTip="Open" Foreground="#C0A020" Content="&#xE838;" />
<Button Name="_saveButton" Style="{StaticResource IconToolButton}" ToolTip="Save" Content="&#xE74E;" />
<Separator Style="{StaticResource VerticalSeparator}" />
<views:UndoRedoView x:Name="_undoRedoView" VerticalAlignment="Stretch" />
</ToolBar>
</ToolBarTray>
<DockingManager Grid.Row="2" x:Name="_dockingManager">
<DockingManager.Resources>
<DataTemplate DataType="{x:Type viewModels:DocumentViewModel}">
<reactiveUi:ViewModelViewHost ViewModel="{Binding}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ShaderFileViewModel}">
<reactiveUi:ViewModelViewHost ViewModel="{Binding}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</DataTemplate>
</DockingManager.Resources>
<DockingManager.DocumentHeaderTemplate>
<DataTemplate DataType="{x:Type LayoutDocument}">
<TextBlock Text="{Binding Content.Name}" />
</DataTemplate>
</DockingManager.DocumentHeaderTemplate>
<DockingManager.Theme>
<Vs2013DarkTheme />
</DockingManager.Theme>
<LayoutRoot>
<LayoutPanel>
<LayoutAnchorablePaneGroup Orientation="Vertical" DockWidth="200">
<LayoutAnchorablePane>
<LayoutAnchorable x:Name="_explorerAnchorable" Title="EXPLORER">
<views:ExplorerView x:Name="_explorerView" />
</LayoutAnchorable>
</LayoutAnchorablePane>
<LayoutAnchorablePane>
<LayoutAnchorable x:Name="_libraryAnchorable" Title="LIBRARY">
<nodeList:NodeListView x:Name="_nodeList" />
</LayoutAnchorable>
</LayoutAnchorablePane>
</LayoutAnchorablePaneGroup>
<LayoutPanel Orientation="Vertical">
<LayoutDocumentPane x:Name="_documentPane" />
<LayoutAnchorablePaneGroup DockHeight="300">
<LayoutAnchorablePane>
<LayoutAnchorable x:Name="_3dViewAnchorable" Title="3D VIEW">
<views:Preview3DView x:Name="_preview3dView" />
</LayoutAnchorable>
</LayoutAnchorablePane>
<LayoutAnchorablePane>
<LayoutAnchorable x:Name="_2dViewAnchorable" Title="2D VIEW">
<views:Preview2DView x:Name="_preview2dView" />
</LayoutAnchorable>
</LayoutAnchorablePane>
</LayoutAnchorablePaneGroup>
</LayoutPanel>
<LayoutAnchorablePane DockWidth="200">
<LayoutAnchorable x:Name="_parametersAnchorable" Title="PARAMETERS">
<views:PropertiesView x:Name="_propertiesView"/>
</LayoutAnchorable>
</LayoutAnchorablePane>
</LayoutPanel>
</LayoutRoot>
</DockingManager>
</Grid>
</Window>

View File

@@ -0,0 +1,84 @@
using System;
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Windows;
using Intromat.Graphics;
using Intromat.ViewModels;
using Microsoft.Win32;
using ReactiveUI;
using Splat;
namespace Intromat.Views
{
public partial class MainWindow : IViewFor<MainViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(MainViewModel), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
var dxHost = Locator.Current.GetService<DxHost>()!;
this.WhenActivated(d =>
{
dxHost.Load(this);
this.Events().Unloaded.Subscribe(_ => dxHost.Unload());
this.OneWayBind(ViewModel, vm => vm.PropertiesContext, v => v._propertiesView.ViewModel).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.Preview2dContext, v => v._preview2dView.ViewModel).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.Preview3dContext, v => v._preview3dView.ViewModel).DisposeWith(d);
//this.OneWayBind(ViewModel, vm => vm.CodePreview, v => v._codePreviewView.ViewModel).DisposeWith(d);
Debug.Assert(ViewModel != null, nameof(ViewModel) + " != null");
ViewModel.OpenProjectFile.RegisterHandler(interaction =>
{
FileDialog dialog;
if (interaction.Input)
dialog = new OpenFileDialog();
else
dialog = new SaveFileDialog();
dialog.FileName = "network.xml";
dialog.AddExtension = true;
dialog.DereferenceLinks = true;
dialog.DefaultExt = "json";
interaction.SetOutput(dialog.ShowDialog() ?? false ? dialog.FileName : null);
});
ViewModel.SelectName.RegisterHandler(interaction =>
{
interaction.SetOutput(UserInputWindow.Show(this, interaction.Input));
});
ViewModel.SelectTypeAndFileName.RegisterHandler(interaction =>
{
interaction.SetOutput(NewFileWindow.Show(this, ViewModel));
});
_dockingManager.DocumentsSource = ViewModel.Files;
this.OneWayBind(ViewModel, vm => vm.Explorer, v => v._explorerView.ViewModel).DisposeWith(d);
this.Bind(ViewModel, vm => vm.ActiveFile, v => v._dockingManager.ActiveContent).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.NodeList, v => v._nodeList.ViewModel).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.UndoRedo, v => v._undoRedoView.ViewModel).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.LoadProject, v => v._openButton.Command).DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.SaveProject, v => v._saveButton.Command).DisposeWith(d);
});
ViewModel = new MainViewModel();
}
public MainViewModel? ViewModel
{
get => (MainViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (MainViewModel?)value;
}
}
}

View File

@@ -0,0 +1,43 @@
<Window x:Class="Intromat.Views.NewFileWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=System.Runtime"
xmlns:views="clr-namespace:Intromat.Views"
WindowStartupLocation="CenterOwner"
ShowInTaskbar="False"
ResizeMode="NoResize"
Style="{DynamicResource CustomWindowStyle}"
mc:Ignorable="d" SizeToContent="Height"
Closing="NewFileWindow_OnClosing"
Title="Intromat" MinHeight="50" Width="300">
<Window.Resources>
<ObjectDataProvider x:Key="supportedFileTypes" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="views:ESupportedFileTypes"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" x:Name="Header" Grid.Row="0" Text="Enter details to create new file:" Margin="5" Grid.ColumnSpan="2" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="Type:" Margin="5" HorizontalAlignment="Right" />
<ComboBox Grid.Column="1" x:Name="Type" Grid.Row="1" Text="" Margin="5,0" ItemsSource="{Binding Source={StaticResource supportedFileTypes}}" SelectionChanged="Type_OnSelectionChanged" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="Name:" Margin="5" HorizontalAlignment="Right" />
<TextBox Grid.Column="1" x:Name="FileName" Grid.Row="2" Text="" Margin="5,0" TextChanged="Name_OnTextChanged" />
<StackPanel Grid.Column="1" Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
<Button x:Name="ButtonOK" IsDefault="True" Width="60" Margin="0,0,2,0" Click="ButtonOK_OnClick">OK</Button>
<Button x:Name="ButtonCancel" IsCancel="True" Width="60" Click="ButtonCancel_OnClick">Cancel</Button>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,89 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using Intromat.ViewModels;
namespace Intromat.Views
{
public enum ESupportedFileTypes
{
Network,
Shader
}
/// <summary>
/// Interaction logic for NewFileWindow.xaml
/// </summary>
public partial class NewFileWindow
{
public NewFileWindow()
{
InitializeComponent();
Type.SelectedItem = ESupportedFileTypes.Network;
}
public Func<FileViewModel>? Result { get; set; }
public static Func<FileViewModel>? Show(Window? owner, MainViewModel mainVm, string? defaultValue = null)
{
var window = new NewFileWindow
{
MainViewModel = mainVm,
Owner = owner
};
if (defaultValue != null)
window.FileName.Text = defaultValue;
window.FileName.SelectAll();
window.FileName.Focus();
window.UpdateResult();
return window.ShowDialog() == true ? window.Result : null;
}
public MainViewModel? MainViewModel { get; set; }
private void Type_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateResult();
}
private void Name_OnTextChanged(object sender, TextChangedEventArgs e)
{
UpdateResult();
}
private void UpdateResult()
{
if (MainViewModel == null)
return;
var module = MainViewModel.Explorer.CurrentModule!;
var parent = MainViewModel.Explorer.CurrentFolder!;
Result = (ESupportedFileTypes)Type.SelectedItem switch
{
ESupportedFileTypes.Network => () => new DocumentViewModel(MainViewModel, module, parent, FileName.Text),
ESupportedFileTypes.Shader => () => new ShaderFileViewModel(MainViewModel, module, parent, FileName.Text),
_ => throw new NotImplementedException()
};
}
private void ButtonOK_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void ButtonCancel_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void NewFileWindow_OnClosing(object sender, CancelEventArgs e)
{
if (DialogResult != true)
Result = null;
}
}
}

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="Intromat.Views.Preview2DView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Intromat.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:DxView x:Name="_dxView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseWheel="OnDxViewMouseWheel">
<local:DxView.RenderTransform>
<MatrixTransform />
</local:DxView.RenderTransform>
</local:DxView>
</Grid>
</UserControl>

View File

@@ -0,0 +1,77 @@
using System;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Intromat.Graphics;
using Intromat.Pipelines;
using Intromat.ViewModels.Previews;
using ReactiveUI;
using SharpDX.Direct3D11;
using Splat;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for Preview2DView.xaml
/// </summary>
public partial class Preview2DView : IViewFor<DxTexturePreviewViewModel>
{
private DisplayTexturePipeline? _pipeline;
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(DxTexturePreviewViewModel), typeof(Preview2DView), new PropertyMetadata(null));
public Preview2DView()
{
InitializeComponent();
this.WhenActivated(d =>
{
_pipeline = Locator.Current.GetService<DisplayTexturePipeline>()!;
this.WhenAnyObservable(v => v.ViewModel!.TextureValue).Subscribe(textureValue =>
{
var srv = textureValue?.ShaderResourceView;
if (srv != null)
{
_pipeline.ShaderResourceView = srv;
_dxView.Render();
}
}).DisposeWith(d);
_dxView.SetUpdateHandler(UpdateFrameAction);
});
}
private void UpdateFrameAction(Device device, DeviceContext context)
{
var graphicsAnalysis = Locator.Current.GetService<DxHost>()?._graphicsAnalysis;
graphicsAnalysis?.BeginCapture();
_pipeline?.Apply();
graphicsAnalysis?.EndCapture();
}
private void OnDxViewMouseWheel(object sender, MouseWheelEventArgs e)
{
var element = (UIElement)sender;
var position = e.GetPosition(element);
var transform = (MatrixTransform)element.RenderTransform;
var matrix = transform.Matrix;
var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1); // choose appropriate scaling factor
matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
transform.Matrix = matrix;
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (DxTexturePreviewViewModel?)value;
}
public DxTexturePreviewViewModel? ViewModel
{
get => (DxTexturePreviewViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
}
}

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="Intromat.Views.Preview3DView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Intromat.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:DxView x:Name="_dxView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseWheel="OnDxViewMouseWheel">
<local:DxView.RenderTransform>
<MatrixTransform />
</local:DxView.RenderTransform>
</local:DxView>
</Grid>
</UserControl>

View File

@@ -0,0 +1,77 @@
using System;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Intromat.Graphics;
using Intromat.Pipelines;
using Intromat.ViewModels.Previews;
using ReactiveUI;
using SharpDX.Direct3D11;
using Splat;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for Preview3DView.xaml
/// </summary>
public partial class Preview3DView : IViewFor<DxMeshPreviewViewModel>
{
private DisplayMeshPipeline? _pipeline;
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(DxMeshPreviewViewModel), typeof(Preview3DView), new PropertyMetadata(null));
public Preview3DView()
{
InitializeComponent();
this.WhenActivated(d =>
{
_pipeline = Locator.Current.GetService<DisplayMeshPipeline>()!;
this.WhenAnyObservable(v => v.ViewModel!.MeshValue).Subscribe(textureValue =>
{
//var srv = textureValue?.ShaderResourceView;
//if (srv != null)
//{
// _pipeline.ShaderResourceView = srv;
// _dxView.Render();
//}
}).DisposeWith(d);
_dxView.SetUpdateHandler(UpdateFrameAction);
});
}
private void UpdateFrameAction(Device device, DeviceContext context)
{
var graphicsAnalysis = Locator.Current.GetService<DxHost>()?._graphicsAnalysis;
graphicsAnalysis?.BeginCapture();
_pipeline?.Apply();
graphicsAnalysis?.EndCapture();
}
private void OnDxViewMouseWheel(object sender, MouseWheelEventArgs e)
{
var element = (UIElement)sender;
var position = e.GetPosition(element);
var transform = (MatrixTransform)element.RenderTransform;
var matrix = transform.Matrix;
var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1); // choose appropriate scaling factor
matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
transform.Matrix = matrix;
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (DxMeshPreviewViewModel?)value;
}
public DxMeshPreviewViewModel? ViewModel
{
get => (DxMeshPreviewViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
}
}

View File

@@ -0,0 +1,12 @@
<UserControl x:Class="Intromat.Views.Previews.DxMeshPreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:Intromat.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="5">
<views:DxView x:Name="_dxView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,63 @@
using System;
using System.Reactive.Disposables;
using Intromat.Graphics;
using Intromat.Pipelines;
using Intromat.ViewModels;
using Intromat.ViewModels.Previews;
using ReactiveUI;
using SharpDX.Direct3D11;
using Splat;
namespace Intromat.Views.Previews
{
/// <summary>
/// Interaction logic for DxMeshPreview.xaml
/// </summary>
public partial class DxMeshPreview : IViewFor<DxMeshPreviewViewModel>
{
private DisplayMeshPipeline? _pipeline;
public DxMeshPreview()
{
InitializeComponent();
MouseDoubleClick += (_, _) =>
{
if (ViewModel == null)
return;
var network = (CodeGenNetworkViewModel)ViewModel.Parent.Parent;
var main = network.Document.MainViewModel;
main.Preview3dContext = ViewModel;
};
this.WhenActivated(d =>
{
_pipeline = Locator.Current.GetService<DisplayMeshPipeline>()!;
this.WhenAnyObservable(v => v.ViewModel!.MeshValue).Subscribe(meshValue =>
{
//var srv = meshValue?.ShaderResourceView;
//if (srv != null)
//{
// _pipeline.ShaderResourceView = srv;
// _dxView.Render();
//}
}).DisposeWith(d);
_dxView.SetUpdateHandler(UpdateFrameAction);
});
}
private void UpdateFrameAction(Device device, DeviceContext context)
{
_pipeline?.Apply();
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (DxMeshPreviewViewModel?)value;
}
public DxMeshPreviewViewModel? ViewModel { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
<UserControl x:Class="Intromat.Views.Previews.DxTexturePreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:Intromat.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="5">
<views:DxView x:Name="_dxView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,63 @@
using System;
using System.Reactive.Disposables;
using Intromat.Graphics;
using Intromat.Pipelines;
using Intromat.ViewModels;
using Intromat.ViewModels.Previews;
using ReactiveUI;
using SharpDX.Direct3D11;
using Splat;
namespace Intromat.Views.Previews
{
/// <summary>
/// Interaction logic for DxTexturePreview.xaml
/// </summary>
public partial class DxTexturePreview : IViewFor<DxTexturePreviewViewModel>
{
private DisplayTexturePipeline? _pipeline;
public DxTexturePreview()
{
InitializeComponent();
MouseDoubleClick += (_, _) =>
{
if (ViewModel == null)
return;
var network = (CodeGenNetworkViewModel)ViewModel.Parent.Parent;
var main = network.Document.MainViewModel;
main.Preview2dContext = ViewModel;
};
this.WhenActivated(d =>
{
_pipeline = Locator.Current.GetService<DisplayTexturePipeline>()!;
this.WhenAnyObservable(v => v.ViewModel!.TextureValue).Subscribe(textureValue =>
{
var srv = textureValue?.ShaderResourceView;
if (srv != null)
{
_pipeline.ShaderResourceView = srv;
_dxView.Render();
}
}).DisposeWith(d);
_dxView.SetUpdateHandler(UpdateFrameAction);
});
}
private void UpdateFrameAction(Device device, DeviceContext context)
{
_pipeline?.Apply();
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (DxTexturePreviewViewModel?)value;
}
public DxTexturePreviewViewModel? ViewModel { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
<UserControl x:Class="Intromat.Views.Previews.StringPreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Intromat.Views.Previews"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock x:Name="_textBlock" TextTrimming="WordEllipsis" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextAlignment="Center" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,30 @@
using System.Reactive.Disposables;
using Intromat.ViewModels.Previews;
using ReactiveUI;
namespace Intromat.Views.Previews
{
/// <summary>
/// Interaction logic for StringPreview.xaml
/// </summary>
public partial class StringPreview : IViewFor<StringPreviewViewModel>
{
public StringPreview()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.Bind(ViewModel, vm => vm.Value, v => v._textBlock.Text).DisposeWith(d);
});
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (StringPreviewViewModel?)value;
}
public StringPreviewViewModel? ViewModel { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
<UserControl x:Class="Intromat.Views.PropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<xctk:PropertyGrid x:Name="PropertyGrid" ShowSortOptions="False" AutoGenerateProperties="False" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,71 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using DynamicData;
using Intromat.ViewModels;
using ReactiveUI;
using Xceed.Wpf.Toolkit.PropertyGrid;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for PropertiesView.xaml
/// </summary>
public partial class PropertiesView : IViewFor<CodeGenNetworkViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(CodeGenNetworkViewModel), typeof(PropertiesView), new PropertyMetadata(null));
public PropertiesView()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.WhenAnyValue(v => v.ViewModel!.SelectedObject!.PropertyDescriptors)
.Where(l => l != null)
.Select(l => l!.Connect())
.Switch()
.Subscribe(_ => PropertyGrid.PropertyDefinitions = CreatePropertyDefinitions(ViewModel!.SelectedObject!.PropertyDescriptors))
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.SelectedObject, v => v.PropertyGrid.SelectedObject).DisposeWith(d);
});
}
private PropertyDefinitionCollection CreatePropertyDefinitions(IObservableList<PropertyDescriptor>? propertyDescriptors)
{
var result = new PropertyDefinitionCollection();
if (propertyDescriptors != null)
result.AddRange(propertyDescriptors.Items.Select(PropertySelector));
return result;
}
private PropertyDefinition PropertySelector(PropertyDescriptor descriptor)
{
return new()
{
Category = descriptor.Category,
Description = descriptor.Description,
IsBrowsable = descriptor.IsBrowsable,
DisplayName = descriptor.DisplayName,
TargetProperties = new [] { descriptor.Name }
};
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CodeGenNetworkViewModel?)value;
}
public CodeGenNetworkViewModel? ViewModel
{
get => (CodeGenNetworkViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
}
}

View File

@@ -0,0 +1,14 @@
<UserControl x:Class="Intromat.Views.ShaderFileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Intromat.Views"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:controls="clr-namespace:Intromat.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<controls:SourceEditor x:Name="_textEditor" ShowLineNumbers="True" SyntaxHighlighting="HLSL" Background="{DynamicResource BackgroundColor}" FontFamily="Consolas" FontSize="14" Foreground="{DynamicResource ControlDefaultForeground}" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,44 @@
using System;
using System.IO;
using System.Reactive.Disposables;
using System.Windows;
using System.Xml;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for ShaderFileView.xaml
/// </summary>
public partial class ShaderFileView : IViewFor<ShaderFileViewModel>
{
static ShaderFileView()
{
using var s = Application.GetResourceStream(new Uri("Resources/HLSL-Mode.xshd", UriKind.Relative))!.Stream;
using var reader = new XmlTextReader(s);
HighlightingManager.Instance.RegisterHighlighting("HLSL", new string[0], HighlightingLoader.Load(reader, HighlightingManager.Instance));
}
public ShaderFileView()
{
InitializeComponent();
this.WhenActivated(d =>
{
var documentViewModel = ViewModel!;
this.Bind(documentViewModel, vm => vm.Source, v => v._textEditor.Text).DisposeWith(d);
});
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (ShaderFileViewModel?)value;
}
public ShaderFileViewModel? ViewModel { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
<Window x:Class="Intromat.Views.SplashScreenWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
WindowStyle="None"
WindowStartupLocation="CenterScreen"
AllowsTransparency="True"
Background="Transparent"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
Title="SplashScreenWindow">
<Border Background="#C0242424" CornerRadius="5" BorderBrush="#a0a0a0" BorderThickness="1" Padding="10">
<StackPanel Orientation="Vertical">
<Image Source="{StaticResource LogoImageSource}" Width="400" Height="400" />
<TextBlock Text="Intromat" VerticalAlignment="Bottom" HorizontalAlignment="Center" FontSize="96" Margin="0,-30,0,0"></TextBlock>
</StackPanel>
</Border>
</Window>

View File

@@ -0,0 +1,15 @@
using System.Windows;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for SplashScreenWindow.xaml
/// </summary>
public partial class SplashScreenWindow : Window
{
public SplashScreenWindow()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,12 @@
<UserControl x:Class="Intromat.Views.UndoRedoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="800">
<StackPanel Orientation="Horizontal">
<Button Name="undoButton" Style="{StaticResource IconToolButton}" ToolTip="Undo" Content="&#xE7A7;" />
<Button Name="redoButton" Style="{StaticResource IconToolButton}" ToolTip="Redo" Content="&#xE7A6;" />
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,41 @@
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Windows;
using Intromat.ViewModels;
using ReactiveUI;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for UndoRedoView.xaml
/// </summary>
public partial class UndoRedoView : IViewFor<UndoRedoViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(UndoRedoViewModel), typeof(UndoRedoView), new PropertyMetadata(null));
public UndoRedoView()
{
InitializeComponent();
this.WhenActivated(d =>
{
Debug.Assert(ViewModel != null, nameof(ViewModel) + " != null");
this.BindCommand(ViewModel, vm => vm.UndoCommand, v => v.undoButton).DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.RedoCommand, v => v.redoButton).DisposeWith(d);
});
}
public UndoRedoViewModel? ViewModel
{
get => (UndoRedoViewModel?)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (UndoRedoViewModel?)value;
}
}
}

View File

@@ -0,0 +1,26 @@
<Window x:Class="Intromat.Views.UserInputWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
WindowStartupLocation="CenterOwner"
ShowInTaskbar="False"
ResizeMode="NoResize"
Style="{DynamicResource CustomWindowStyle}"
mc:Ignorable="d" SizeToContent="Height"
Closing="UserInputWindow_OnClosing"
Title="Intromat" MinHeight="50" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock x:Name="Header" Grid.Row="0" Text="Enter data:" Margin="5" />
<TextBox x:Name="Input" Grid.Row="1" Text="" Margin="5,0" TextChanged="Input_OnTextChanged" />
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
<Button x:Name="ButtonOK" IsDefault="True" Width="60" Margin="0,0,2,0" Click="ButtonOK_OnClick">OK</Button>
<Button x:Name="ButtonCancel" IsCancel="True" Width="60" Click="ButtonCancel_OnClick">Cancel</Button>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,57 @@
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Intromat.Views
{
/// <summary>
/// Interaction logic for UserInputWindow.xaml
/// </summary>
public partial class UserInputWindow
{
public UserInputWindow()
{
InitializeComponent();
}
public string? Result { get; set; }
public static string? Show(Window? owner, string? header, string? title = null, string? defaultValue = null)
{
var window = new UserInputWindow
{
Owner = owner,
Title = title ?? "Intromat",
Header = { Text = header ?? "Enter value:" }
};
if (defaultValue != null)
window.Input.Text = window.Result = defaultValue;
window.Input.SelectAll();
window.Input.Focus();
return window.ShowDialog() == true ? window.Result : null;
}
private void Input_OnTextChanged(object sender, TextChangedEventArgs e)
{
Result = Input.Text;
}
private void ButtonOK_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void ButtonCancel_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void UserInputWindow_OnClosing(object sender, CancelEventArgs e)
{
if (DialogResult != true)
Result = null;
}
}
}