port from perforce
This commit is contained in:
9
intromat/NodeNetwork/.editorconfig
Normal file
9
intromat/NodeNetwork/.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
[*.cs]
|
||||
|
||||
dotnet_diagnostic.IDE0019.severity = none
|
||||
dotnet_diagnostic.IDE0038.severity = none
|
||||
dotnet_diagnostic.IDE0044.severity = none
|
||||
dotnet_diagnostic.IDE0052.severity = none
|
||||
dotnet_diagnostic.IDE0058.severity = none
|
||||
dotnet_diagnostic.IDE0062.severity = none
|
||||
dotnet_diagnostic.IDE0090.severity = none
|
||||
8
intromat/NodeNetwork/GlobalSuppressions.cs
Normal file
8
intromat/NodeNetwork/GlobalSuppressions.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
68
intromat/NodeNetwork/NNViewRegistrar.cs
Normal file
68
intromat/NodeNetwork/NNViewRegistrar.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NodeNetwork.ViewModels;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork
|
||||
{
|
||||
/// <summary>
|
||||
/// A locator is used to find the correct view corresponding to a viewmodel.
|
||||
/// In ReactiveUI, usually Splat is used, but others exist. This class acts as an intermediate registrar.
|
||||
/// It gathers registrations and registers them to the preferred locator.
|
||||
/// </summary>
|
||||
public sealed class NNViewRegistrar
|
||||
{
|
||||
private static readonly List<Tuple<Func<object>, Type>> PendingRegistrations = new List<Tuple<Func<object>, Type>>();
|
||||
private static Action<Func<object>, Type> _registerAction;
|
||||
|
||||
public static void AddRegistration(Func<object> factory, Type serviceType)
|
||||
{
|
||||
if (factory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
else if (serviceType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serviceType));
|
||||
}
|
||||
|
||||
if (_registerAction == null)
|
||||
{
|
||||
PendingRegistrations.Add(Tuple.Create(factory, serviceType));
|
||||
}
|
||||
else
|
||||
{
|
||||
_registerAction(factory, serviceType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterToLocator(Action<Func<object>, Type> newRegisterAction)
|
||||
{
|
||||
if (newRegisterAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(newRegisterAction));
|
||||
}
|
||||
else if (_registerAction != null)
|
||||
{
|
||||
throw new InvalidOperationException("A locator has already been set");
|
||||
}
|
||||
|
||||
_registerAction = newRegisterAction;
|
||||
foreach (var t in PendingRegistrations)
|
||||
{
|
||||
_registerAction(t.Item1, t.Item2);
|
||||
}
|
||||
PendingRegistrations.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register all NodeNetwork view/viewmodel pairs to Locator.CurrentMutable.
|
||||
/// </summary>
|
||||
public static void RegisterSplat()
|
||||
{
|
||||
RegisterToLocator((f, t) => Locator.CurrentMutable.Register(f, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
intromat/NodeNetwork/NodeNetwork.csproj
Normal file
39
intromat/NodeNetwork/NodeNetwork.csproj
Normal file
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0-windows7.0;net48</TargetFrameworks>
|
||||
<OutputType>library</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>6.0.0</Version>
|
||||
<Authors>Wouter De Keersmaecker</Authors>
|
||||
<PackageTags>wpf reactiveui node network editor node-editor graph</PackageTags>
|
||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://www.github.com/wouterdek/nodenetwork</RepositoryUrl>
|
||||
<RepositoryType>Github</RepositoryType>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\Release\NodeNetwork.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="log4net" Version="2.0.12" />
|
||||
<PackageReference Include="ReactiveUI" Version="13.2.18" />
|
||||
<PackageReference Include="ReactiveUI.Events.WPF" Version="13.2.18" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="13.2.18" />
|
||||
<PackageReference Include="Splat.Drawing" Version="11.0.1" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Drawing.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
55
intromat/NodeNetwork/Properties/AssemblyInfo.cs
Normal file
55
intromat/NodeNetwork/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("NodeNetwork")]
|
||||
[assembly: AssemblyDescription("A library with a WPF node editor component based on ReactiveUI")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NodeNetwork")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) Wouter De Keersmaecker")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly:ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.0.0")]
|
||||
74
intromat/NodeNetwork/Themes/ConnectionView.xaml
Normal file
74
intromat/NodeNetwork/Themes/ConnectionView.xaml
Normal file
@@ -0,0 +1,74 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:controls="clr-namespace:NodeNetwork.Views.Controls">
|
||||
<Style TargetType="{x:Type views:ConnectionView}">
|
||||
<Setter Property="RegularBrush" Value="White"/>
|
||||
<Setter Property="ErrorBrush" Value="DarkRed"/>
|
||||
<Setter Property="HighlightBrush" Value="Yellow"/>
|
||||
<Setter Property="MarkedForDeleteBrush" Value="Red"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:ConnectionView">
|
||||
<controls:FillPanel>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup Name="{x:Static views:ConnectionView.HighlightVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:ConnectionView.HighlightedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="HighlightPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:ConnectionView.NonHighlightedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="HighlightPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup Name="{x:Static views:ConnectionView.ErrorVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:ConnectionView.ErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:ConnectionView.NonErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup Name="{x:Static views:ConnectionView.MarkedForDeleteVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:ConnectionView.MarkedForDeleteState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DeleteMarkPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:ConnectionView.NotMarkedForDeleteState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DeleteMarkPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Path x:Name="RegularPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding RegularBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
<Path x:Name="ErrorPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding ErrorBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
<Path x:Name="DeleteMarkPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding MarkedForDeleteBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
<Path x:Name="HighlightPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding HighlightBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
</controls:FillPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
53
intromat/NodeNetwork/Themes/Endpoint.xaml
Normal file
53
intromat/NodeNetwork/Themes/Endpoint.xaml
Normal file
@@ -0,0 +1,53 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:reactiveUi="http://reactiveui.net"
|
||||
xmlns:wpf="clr-namespace:NodeNetwork.Utilities.WPF">
|
||||
<wpf:NullVisibilityConverter x:Key="NullConverter"/>
|
||||
<ControlTemplate x:Key="LeftAlignedEndpoint">
|
||||
<Grid Margin="-10, 0, 0, 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="30"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" VerticalAlignment="Center">
|
||||
<Image x:Name="Icon" MaxWidth="20" MaxHeight="20" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,5,0" Visibility="{Binding Icon, Mode=OneWay, Converter={StaticResource NullConverter}}"/>
|
||||
<TextBlock x:Name="NameLabel" TextTrimming="CharacterEllipsis" FontSize="14" Width="auto" Foreground="White" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<reactiveUi:ViewModelViewHost x:Name="EndpointHost" Grid.Column="0" Grid.Row="0" Margin="0,4.9,10,4.9" Width="20" Height="20"
|
||||
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
|
||||
<reactiveUi:ViewModelViewHost x:Name="EditorHost" Grid.Column="1" VerticalContentAlignment="Center" IsTabStop="False"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="RightAlignedEndpoint">
|
||||
<Grid Margin="0, 0, -10, 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right">
|
||||
<TextBlock x:Name="NameLabel" TextTrimming="CharacterEllipsis" FontSize="14" Width="auto" Foreground="White" VerticalAlignment="Center"/>
|
||||
<Image x:Name="Icon" MaxWidth="20" MaxHeight="20" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,0,0,0" Visibility="{Binding Icon, Mode=OneWay, Converter={StaticResource NullConverter}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<reactiveUi:ViewModelViewHost x:Name="EndpointHost" Grid.Column="2" Grid.Row="0" Margin="10,4.9,0,4.9" Width="20" Height="20"
|
||||
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
|
||||
<reactiveUi:ViewModelViewHost x:Name="EditorHost" Grid.Column="1" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" HorizontalAlignment="Right" IsTabStop="False"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</ResourceDictionary>
|
||||
102
intromat/NodeNetwork/Themes/EndpointGroupView.xaml
Normal file
102
intromat/NodeNetwork/Themes/EndpointGroupView.xaml
Normal file
@@ -0,0 +1,102 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:reactiveUi="http://reactiveui.net"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:viewModels="clr-namespace:NodeNetwork.ViewModels">
|
||||
<Style TargetType="{x:Type views:EndpointGroupView}">
|
||||
<Setter Property="Background" Value="#20000000"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="TitleFontFamily" Value="Segoe UI SemiLight"/>
|
||||
<Setter Property="TitleFontSize" Value="18"/>
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:EndpointGroupView">
|
||||
<Grid Margin="0,5,0,0">
|
||||
<Canvas Background="{TemplateBinding Background}" IsHitTestVisible="False"/>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<DockPanel Margin="0,5,0,0">
|
||||
<TextBlock x:Name="NameLabel" TextTrimming="CharacterEllipsis" FontSize="{TemplateBinding TitleFontSize}" FontFamily="{TemplateBinding TitleFontFamily}"
|
||||
Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" Margin="20,0,10,0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Text" Value="">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="Text" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<ItemsControl x:Name="InputsList" IsTabStop="False">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Vertical">
|
||||
<Setter Property="DockPanel.Dock" Value="Top" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Horizontal">
|
||||
<Setter Property="DockPanel.Dock" Value="Left" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:NodeInputViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<ItemsControl x:Name="OutputsList" IsTabStop="False">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}"
|
||||
Value="Vertical">
|
||||
<Setter Property="DockPanel.Dock" Value="Bottom" />
|
||||
</DataTrigger>
|
||||
<DataTrigger
|
||||
Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}"
|
||||
Value="Horizontal">
|
||||
<Setter Property="DockPanel.Dock" Value="Right" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:NodeOutputViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</DockPanel>
|
||||
<ItemsControl x:Name="EndpointGroupsList" IsTabStop="False">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:EndpointGroupViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
26
intromat/NodeNetwork/Themes/ErrorMessageView.xaml
Normal file
26
intromat/NodeNetwork/Themes/ErrorMessageView.xaml
Normal file
@@ -0,0 +1,26 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views">
|
||||
<Style TargetType="{x:Type views:ErrorMessageView}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:ErrorMessageView">
|
||||
<Border Background="#EEE" CornerRadius="3">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="36" Height="36" Margin="5">
|
||||
<Ellipse Fill="#ef513a"/>
|
||||
<Line Stroke="White" StrokeThickness="3" X1="12" Y1="12" X2="24" Y2="24"/>
|
||||
<Line Stroke="White" StrokeThickness="3" X1="24" Y1="12" X2="12" Y2="24"/>
|
||||
</Grid>
|
||||
<TextBlock Grid.Column="1" x:Name="TextBlock" Margin="5" TextWrapping="Wrap" FontSize="18" FontWeight="Normal" Foreground="#ef513a" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
13
intromat/NodeNetwork/Themes/Generic.xaml
Normal file
13
intromat/NodeNetwork/Themes/Generic.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/ConnectionView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/PendingConnectionView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/ErrorMessageView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/NodeEndpointEditorView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/NodeView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/NodeInputView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/NodeOutputView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/PortView.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/NodeNetwork;component/Themes/EndpointGroupView.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
13
intromat/NodeNetwork/Themes/NodeEndpointEditorView.xaml
Normal file
13
intromat/NodeNetwork/Themes/NodeEndpointEditorView.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views">
|
||||
<Style TargetType="{x:Type views:NodeEndpointEditorView}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:NodeEndpointEditorView">
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
24
intromat/NodeNetwork/Themes/NodeInputView.xaml
Normal file
24
intromat/NodeNetwork/Themes/NodeInputView.xaml
Normal file
@@ -0,0 +1,24 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:viewModels="clr-namespace:NodeNetwork.ViewModels">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Endpoint.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style TargetType="{x:Type views:NodeInputView}">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=PortPosition}" Value="{x:Static viewModels:PortPosition.Left}">
|
||||
<DataTrigger.Setters>
|
||||
<Setter Property="Template" Value="{StaticResource LeftAlignedEndpoint}"/>
|
||||
</DataTrigger.Setters>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=PortPosition}" Value="{x:Static viewModels:PortPosition.Right}">
|
||||
<DataTrigger.Setters>
|
||||
<Setter Property="Template" Value="{StaticResource RightAlignedEndpoint}"/>
|
||||
</DataTrigger.Setters>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
24
intromat/NodeNetwork/Themes/NodeOutputView.xaml
Normal file
24
intromat/NodeNetwork/Themes/NodeOutputView.xaml
Normal file
@@ -0,0 +1,24 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:viewModels="clr-namespace:NodeNetwork.ViewModels">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Endpoint.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style TargetType="{x:Type views:NodeOutputView}">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=PortPosition}" Value="{x:Static viewModels:PortPosition.Left}">
|
||||
<DataTrigger.Setters>
|
||||
<Setter Property="Template" Value="{StaticResource LeftAlignedEndpoint}"/>
|
||||
</DataTrigger.Setters>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=PortPosition}" Value="{x:Static viewModels:PortPosition.Right}">
|
||||
<DataTrigger.Setters>
|
||||
<Setter Property="Template" Value="{StaticResource RightAlignedEndpoint}"/>
|
||||
</DataTrigger.Setters>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
175
intromat/NodeNetwork/Themes/NodeView.xaml
Normal file
175
intromat/NodeNetwork/Themes/NodeView.xaml
Normal file
@@ -0,0 +1,175 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:controls="clr-namespace:NodeNetwork.Views.Controls"
|
||||
xmlns:viewModels="clr-namespace:NodeNetwork.ViewModels"
|
||||
xmlns:reactiveUi="http://reactiveui.net">
|
||||
<Style TargetType="{x:Type views:NodeView}">
|
||||
<Setter Property="Background" Value="#5D9CEC"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="TitleFontFamily" Value="Segoe UI Semibold"/>
|
||||
<Setter Property="TitleFontSize" Value="18"/>
|
||||
<Setter Property="BorderBrush" Value="Orange"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="ArrowSize" Value="20"/>
|
||||
<Setter Property="EndpointsStackingOrientation" Value="Vertical"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:NodeView">
|
||||
<controls:FillPanel x:Name="Container">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup Name="{x:Static views:NodeView.SelectedVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:NodeView.SelectedState}">
|
||||
<Storyboard>
|
||||
<ThicknessAnimation Duration="0" To="-3"
|
||||
Storyboard.TargetName="Container" Storyboard.TargetProperty="Margin"/>
|
||||
<ThicknessAnimation Duration="0" To="3" Storyboard.TargetName="Border" Storyboard.TargetProperty="BorderThickness"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:NodeView.UnselectedState}">
|
||||
<Storyboard>
|
||||
<ThicknessAnimation Duration="0" To="0" Storyboard.TargetName="Container" Storyboard.TargetProperty="Margin"/>
|
||||
<ThicknessAnimation Duration="0" To="0" Storyboard.TargetName="Border" Storyboard.TargetProperty="BorderThickness"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<Border x:Name="Border" Margin="10,0,10,0" CornerRadius="{TemplateBinding CornerRadius}"
|
||||
MinWidth="100" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
|
||||
<Grid>
|
||||
<Thumb VerticalAlignment="Bottom" Height="10" x:Name="ResizeVerticalThumb" Cursor="SizeNS">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate>
|
||||
<Canvas Background="White" Opacity="0"/>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="Horizontal">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="None">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
<Thumb HorizontalAlignment="Right" Width="10" x:Name="ResizeHorizontalThumb" Cursor="SizeWE">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate>
|
||||
<Canvas Background="White" Opacity="0"/>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="Vertical">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="None">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
<Thumb HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="10" Height="10" x:Name="ResizeDiagonalThumb" Cursor="SizeNWSE">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate>
|
||||
<Canvas Background="White" Opacity="0"/>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="Vertical">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="Horizontal">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Resizable}" Value="None">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
<StackPanel>
|
||||
<Canvas x:Name="HeaderTopMargin" Width="auto" Height="10"/>
|
||||
<DockPanel>
|
||||
<Image x:Name="HeaderIcon" MaxWidth="{TemplateBinding ArrowSize}" MaxHeight="{TemplateBinding ArrowSize}" DockPanel.Dock="Left" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"/>
|
||||
<TextBlock x:Name="NameLabel" TextWrapping="Wrap" Background="Transparent" Foreground="{TemplateBinding Foreground}" DockPanel.Dock="Left" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center"
|
||||
FontFamily="{TemplateBinding TitleFontFamily}" FontSize="{TemplateBinding TitleFontSize}" Margin="10,0,0,0"/>
|
||||
<controls:ArrowToggleButton x:Name="CollapseButton" Width="{TemplateBinding ArrowSize}" Height="{TemplateBinding ArrowSize}" DockPanel.Dock="Right" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0,10,0"/>
|
||||
</DockPanel>
|
||||
<Canvas x:Name="HeaderBottomMargin" Width="auto" Height="3"/>
|
||||
|
||||
<ContentPresenter x:Name="LeadingControlPresenter" Style="{TemplateBinding LeadingControlPresenterStyle}"/>
|
||||
|
||||
<DockPanel>
|
||||
<ItemsControl x:Name="InputsList" IsTabStop="False">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Vertical">
|
||||
<Setter Property="DockPanel.Dock" Value="Top"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Horizontal">
|
||||
<Setter Property="DockPanel.Dock" Value="Left"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:NodeInputViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<ItemsControl x:Name="OutputsList" IsTabStop="False">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Vertical">
|
||||
<Setter Property="DockPanel.Dock" Value="Bottom"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=EndpointsStackingOrientation, RelativeSource={RelativeSource AncestorType={x:Type views:NodeView}}}" Value="Horizontal">
|
||||
<Setter Property="DockPanel.Dock" Value="Right"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:NodeOutputViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</DockPanel>
|
||||
<ItemsControl x:Name="EndpointGroupsList" IsTabStop="False">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:EndpointGroupViewModel">
|
||||
<reactiveUi:ViewModelViewHost ViewModel="{Binding}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<ContentPresenter x:Name="TrailingControlPresenter" Style="{TemplateBinding TrailingControlPresenterStyle}"/>
|
||||
|
||||
<Canvas x:Name="BottomMargin" Width="auto" Height="5"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</controls:FillPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
44
intromat/NodeNetwork/Themes/PendingConnectionView.xaml
Normal file
44
intromat/NodeNetwork/Themes/PendingConnectionView.xaml
Normal file
@@ -0,0 +1,44 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:controls="clr-namespace:NodeNetwork.Views.Controls">
|
||||
<Style TargetType="{x:Type views:PendingConnectionView}">
|
||||
<Setter Property="RegularBrush" Value="#C8FFFFFF"/>
|
||||
<Setter Property="ErrorBrush" Value="#C8FF0000"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:PendingConnectionView">
|
||||
<controls:FillPanel>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup Name="{x:Static views:PendingConnectionView.ErrorVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:PendingConnectionView.ErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="RegularPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:PendingConnectionView.NonErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="RegularPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorPath" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Path x:Name="RegularPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding RegularBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
<Path x:Name="ErrorPath" StrokeThickness="2" IsHitTestVisible="False" Stroke="{TemplateBinding ErrorBrush}" Data="{TemplateBinding Geometry}"/>
|
||||
</controls:FillPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
78
intromat/NodeNetwork/Themes/PortView.xaml
Normal file
78
intromat/NodeNetwork/Themes/PortView.xaml
Normal file
@@ -0,0 +1,78 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:NodeNetwork.Views"
|
||||
xmlns:controls="clr-namespace:NodeNetwork.Views.Controls">
|
||||
<Style TargetType="{x:Type views:PortView}">
|
||||
<Setter Property="RegularStroke" Value="#9E9E9E"/>
|
||||
<Setter Property="RegularFill" Value="#E0E0E0"/>
|
||||
<Setter Property="ConnectedStroke" Value="#AEAEAE"/>
|
||||
<Setter Property="ConnectedFill" Value="#F0F0F0"/>
|
||||
<Setter Property="HighlightStroke" Value="#30FFFFFF"/>
|
||||
<Setter Property="HighlightFill" Value="#30FFFFFF"/>
|
||||
<Setter Property="ErrorStroke" Value="#F44336"/>
|
||||
<Setter Property="ErrorFill" Value="#FFCDD2"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="views:PortView">
|
||||
<controls:FillPanel>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup Name="{x:Static views:PortView.ConnectedVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:PortView.ConnectedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ConnectedEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:PortView.DisconnectedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ConnectedEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup Name="{x:Static views:PortView.HighlightVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:PortView.HighlightedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="HighlightEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:PortView.NonHighlightedState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="HighlightEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup Name="{x:Static views:PortView.ErrorVisualStatesGroup}">
|
||||
<VisualState Name="{x:Static views:PortView.ErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="{x:Static views:PortView.NonErrorState}">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ErrorEllipse" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Ellipse Name="RegularEllipse" StrokeThickness="2" Stroke="{TemplateBinding RegularStroke}" Fill="{TemplateBinding RegularFill}"/>
|
||||
<Ellipse Name="ConnectedEllipse" StrokeThickness="2" Stroke="{TemplateBinding ConnectedStroke}" Fill="{TemplateBinding ConnectedFill}"/>
|
||||
<Ellipse Name="ErrorEllipse" StrokeThickness="2" Stroke="{TemplateBinding ErrorStroke}" Fill="{TemplateBinding ErrorFill}"/>
|
||||
<Ellipse Name="HighlightEllipse" StrokeThickness="2" Stroke="{TemplateBinding HighlightStroke}" Fill="{TemplateBinding HighlightFill}"/>
|
||||
</controls:FillPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
134
intromat/NodeNetwork/Utilities/LongestCommonSubsequence.cs
Normal file
134
intromat/NodeNetwork/Utilities/LongestCommonSubsequence.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NodeNetwork.Utilities
|
||||
{
|
||||
//Class for calculating the longest common subsequence of two lists
|
||||
//For example: the LCS of 'computer' and 'houseboat' is 'out'
|
||||
public class LongestCommonSubsequence
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of change that occured.
|
||||
/// </summary>
|
||||
public enum ChangeType
|
||||
{
|
||||
Removed, Added
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the changes to be made to oldList to reach the state of newList.
|
||||
/// First all items that are in oldList but not in the LCS of oldList and newList are removed.
|
||||
/// The list is then identical to the LCS of oldList and newList.
|
||||
/// Then all items that are in newList but not in the LCS of oldList and newList are added.
|
||||
/// The list is then identical to newList.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items contained in the two lists</typeparam>
|
||||
/// <param name="oldList">The first list</param>
|
||||
/// <param name="newList">The second list</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<(int index, T item, ChangeType change)> GetChanges<T>(IList<T> oldList, IList<T> newList)
|
||||
{
|
||||
if (oldList == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(oldList));
|
||||
}else if (newList == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(newList));
|
||||
}
|
||||
|
||||
T[] lcs = LongestCommonSubsequence.Calculate(oldList, newList).ToArray();
|
||||
|
||||
//Initial data => LCS
|
||||
int lcsCursor = lcs.Length - 1;
|
||||
for (int initialDataCursor = oldList.Count - 1; initialDataCursor >= 0; initialDataCursor--)
|
||||
{
|
||||
if (lcsCursor >= 0 && oldList[initialDataCursor].Equals(lcs[lcsCursor]))
|
||||
{
|
||||
lcsCursor--;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return (initialDataCursor, oldList[initialDataCursor], ChangeType.Removed);
|
||||
}
|
||||
}
|
||||
|
||||
//LCS => newdata
|
||||
lcsCursor = 0;
|
||||
for (int newDataCursor = 0; newDataCursor < newList.Count; newDataCursor++)
|
||||
{
|
||||
if (lcsCursor < lcs.Length && newList[newDataCursor].Equals(lcs[lcsCursor]))
|
||||
{
|
||||
lcsCursor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return (newDataCursor, newList[newDataCursor], ChangeType.Added);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the longest common subsequence of two lists
|
||||
/// For example: the LCS of 'computer' and 'houseboat' is 'out'
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items contained in the two lists</typeparam>
|
||||
/// <param name="seq1">The first list</param>
|
||||
/// <param name="seq2">The second list</param>
|
||||
/// <returns>An enumerable of items that are both in seq1 and seq2 and which follows the consecutive order of both lists</returns>
|
||||
public static IEnumerable<T> Calculate<T>(IList<T> seq1, IList<T> seq2)
|
||||
{
|
||||
int[,] matrix = CalculateLCSMatrix(seq1, seq2);
|
||||
return Backtrack(seq1, seq2, matrix).Reverse();
|
||||
}
|
||||
|
||||
private static int[,] CalculateLCSMatrix<T>(IList<T> seq1, IList<T> seq2)
|
||||
{
|
||||
int[,] matrix = new int[seq1.Count + 1, seq2.Count + 1];
|
||||
for (int i = 1; i < matrix.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 1; j < matrix.GetLength(1); j++)
|
||||
{
|
||||
if (seq1[i - 1].Equals(seq2[j - 1]))
|
||||
{
|
||||
matrix[i, j] = matrix[i - 1, j - 1] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix[i, j] = Math.Max(matrix[i - 1, j], matrix[i, j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
private static IEnumerable<T> Backtrack<T>(IList<T> seq1, IList<T> seq2, int[,] matrix)
|
||||
{
|
||||
int i = matrix.GetLength(0) - 1;
|
||||
int j = matrix.GetLength(1) - 1;
|
||||
bool done = false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (i > 0 && j > 0 && seq1[i - 1].Equals(seq2[j - 1]))
|
||||
{
|
||||
yield return seq1[i - 1];
|
||||
i -= 1;
|
||||
j -= 1;
|
||||
}
|
||||
else if (j > 0 && (i == 0 || matrix[i, j - 1] >= matrix[i - 1, j]))
|
||||
{
|
||||
j -= 1;
|
||||
}
|
||||
else if (i > 0 && (j == 0 || matrix[i, j - 1] < matrix[i - 1, j]))
|
||||
{
|
||||
i -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
intromat/NodeNetwork/Utilities/ReactiveExtensions.cs
Normal file
100
intromat/NodeNetwork/Utilities/ReactiveExtensions.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Utilities
|
||||
{
|
||||
public static class ReactiveExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Pass through values if and only if the last value produced by 'throttleCondition' is false.
|
||||
/// When 'throttleCondition' is false, no values are passed through.
|
||||
/// When 'throttleCondition' changes from true to false, if one or more values was blocked during the period
|
||||
/// in which the throttle was active, the latest value will be passed through.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The datatype in the observable</typeparam>
|
||||
/// <param name="self">The source observable</param>
|
||||
/// <param name="throttleCondition">An observable of booleans that determines the current throttle state</param>
|
||||
/// <returns>The new observable</returns>
|
||||
public static IObservable<T> ThrottleWhen<T>(this IObservable<T> self, IObservable<bool> throttleCondition)
|
||||
{
|
||||
var isPaused = throttleCondition.Prepend(false).DistinctUntilChanged();
|
||||
return Observable.Defer(() =>
|
||||
{
|
||||
object lockObj = new object();
|
||||
bool gateIsOpen = false;
|
||||
return Observable.CombineLatest(
|
||||
self.Synchronize(lockObj).Do(_ => gateIsOpen = true),
|
||||
isPaused.Synchronize(lockObj).Do(paused => gateIsOpen = !paused && gateIsOpen),
|
||||
(number, paused) => (number, paused)
|
||||
)
|
||||
.Where(tuple => !tuple.paused && gateIsOpen)
|
||||
.Select(tuple => tuple.number);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a one way list binding from the viewmodel to the view.
|
||||
/// The view list property will be automatically updated to reflect
|
||||
/// the viewmodel source list property.
|
||||
/// </summary>
|
||||
/// <typeparam name="TView">The type of the view</typeparam>
|
||||
/// <typeparam name="TViewModel">The type of the viewmodel</typeparam>
|
||||
/// <typeparam name="TData">The type of the data stored in the list</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the target property in the view</typeparam>
|
||||
/// <param name="self">The view used for the binding</param>
|
||||
/// <param name="vmDummy">A dummy viewmodel parameter, used to infer the viewmodel type</param>
|
||||
/// <param name="vmProperty">The source property in the viewmodel that contains the list</param>
|
||||
/// <param name="viewProperty">The target property in the view to bind the list to.</param>
|
||||
/// <returns>An object that when disposed, disconnects the binding.</returns>
|
||||
public static IDisposable BindList<TView, TViewModel, TData, TProperty>(
|
||||
this TView self,
|
||||
TViewModel vmDummy,
|
||||
Expression<Func<TViewModel, IObservableList<TData>>> vmProperty,
|
||||
Expression<Func<TView, TProperty>> viewProperty
|
||||
)
|
||||
where TView: class, IViewFor<TViewModel>
|
||||
where TViewModel: class
|
||||
{
|
||||
IDisposable lastBinding = null;
|
||||
|
||||
return
|
||||
// Get latest viewmodel
|
||||
self.WhenAnyValue(v => v.ViewModel)
|
||||
.Where(vm => vm != null)
|
||||
// Get latest non-null list from viewmodel property
|
||||
.Select(vm => vm.WhenAnyValue(vmProperty))
|
||||
.Switch()
|
||||
.Where(sourceList => sourceList != null)
|
||||
// Clean up last list binding
|
||||
.Do(p => lastBinding?.Dispose())
|
||||
// Create new list binding
|
||||
.Select(sourceList =>
|
||||
{
|
||||
lastBinding = sourceList.Connect().Bind(out var list).Subscribe();
|
||||
return list;
|
||||
})
|
||||
// When the observable is disposed, dispose the list binding too
|
||||
.Finally(() =>
|
||||
{
|
||||
lastBinding?.Dispose();
|
||||
})
|
||||
// Bind the new bindable list to the view property
|
||||
.BindTo(self, viewProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes an observable of T values and returns an observable of tuples of T values containing the latest value and the previous value.
|
||||
/// The first item in the source observable produces a tuple with the previous value set to default(T).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of object in the observable</typeparam>
|
||||
/// <param name="obs">The source observable</param>
|
||||
/// <returns>The resulting observable</returns>
|
||||
public static IObservable<(T OldValue, T NewValue)> PairWithPreviousValue<T>(this IObservable<T> obs)
|
||||
{
|
||||
return obs.Scan((oldValue: default(T), newValue: default(T)), (pair, newVal) => (pair.newValue, newVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
22
intromat/NodeNetwork/Utilities/WPF/BoolToZIndexConverter.cs
Normal file
22
intromat/NodeNetwork/Utilities/WPF/BoolToZIndexConverter.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace NodeNetwork.Utilities.WPF
|
||||
{
|
||||
public class BoolToZIndexConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return ((bool) value) ? 1 : 0;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace NodeNetwork.Utilities.WPF
|
||||
{
|
||||
public class NullVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return value == null ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
intromat/NodeNetwork/Utilities/WPF/WPFUtils.cs
Normal file
74
intromat/NodeNetwork/Utilities/WPF/WPFUtils.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace NodeNetwork.Views.Controls
|
||||
{
|
||||
public static class WPFUtils
|
||||
{
|
||||
public static T FindParent<T>(DependencyObject childObject) where T : DependencyObject
|
||||
{
|
||||
DependencyObject curObj = childObject;
|
||||
do
|
||||
{
|
||||
curObj = VisualTreeHelper.GetParent(curObj);
|
||||
if (curObj == null) return default(T);
|
||||
} while (!(curObj is T));
|
||||
return (T)curObj;
|
||||
}
|
||||
|
||||
public static DependencyObject GetVisualAncestorNLevelsUp(DependencyObject childObject, int levels)
|
||||
{
|
||||
DependencyObject curObj = childObject;
|
||||
for (int i = 0; i < levels; i++)
|
||||
{
|
||||
curObj = VisualTreeHelper.GetParent(curObj);
|
||||
if (curObj == null) return null;
|
||||
}
|
||||
return curObj;
|
||||
}
|
||||
|
||||
public static IEnumerable<Point> GetIntersectionPoints(Geometry g1, Geometry g2)
|
||||
{
|
||||
Geometry og1 = g1.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));
|
||||
Geometry og2 = g2.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));
|
||||
|
||||
CombinedGeometry cg = new CombinedGeometry(GeometryCombineMode.Intersect, og1, og2);
|
||||
|
||||
PathGeometry pg = cg.GetFlattenedPathGeometry();
|
||||
foreach (PathFigure figure in pg.Figures)
|
||||
{
|
||||
Rect fig = new PathGeometry(new[] { figure }).Bounds;
|
||||
yield return new Point(fig.Left + fig.Width / 2.0, fig.Top + fig.Height / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindDescendantsOfType<T>(DependencyObject root, bool skipChildrenOnHit) where T : DependencyObject
|
||||
{
|
||||
int childCount = VisualTreeHelper.GetChildrenCount(root);
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
var obj = VisualTreeHelper.GetChild(root, i);
|
||||
if (obj is T t)
|
||||
{
|
||||
yield return t;
|
||||
|
||||
if (skipChildrenOnHit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var subChild in FindDescendantsOfType<T>(obj, skipChildrenOnHit))
|
||||
{
|
||||
yield return subChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
intromat/NodeNetwork/ValidationResult.cs
Normal file
57
intromat/NodeNetwork/ValidationResult.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NodeNetwork
|
||||
{
|
||||
/// <summary>
|
||||
/// A class that represents a generic validation result.
|
||||
/// </summary>
|
||||
public abstract class ValidationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// True if the subject is valid
|
||||
/// </summary>
|
||||
public bool IsValid { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A viewmodel of the message that is to be displayed explaining this validation result.
|
||||
/// </summary>
|
||||
public object MessageViewModel { get; }
|
||||
|
||||
protected ValidationResult(bool isValid, object messageViewModel)
|
||||
{
|
||||
this.IsValid = isValid;
|
||||
this.MessageViewModel = messageViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A validation of the node network.
|
||||
/// </summary>
|
||||
public class NetworkValidationResult : ValidationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// If false, the network is in a state where trying to parse it (by walking from node to node) can cause problems.
|
||||
/// For example, this property is false if the network contains loops since parsing it could then result in infinite loops.
|
||||
/// </summary>
|
||||
public bool NetworkIsTraversable { get; }
|
||||
|
||||
public NetworkValidationResult(bool isValid, bool isTraversable, object messageViewModel) : base(isValid, messageViewModel)
|
||||
{
|
||||
NetworkIsTraversable = isTraversable;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A validation of a connection between nodes.
|
||||
/// </summary>
|
||||
public class ConnectionValidationResult : ValidationResult
|
||||
{
|
||||
public ConnectionValidationResult(bool isValid, object messageViewModel) : base(isValid, messageViewModel)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
100
intromat/NodeNetwork/ViewModels/ConnectionViewModel.cs
Normal file
100
intromat/NodeNetwork/ViewModels/ConnectionViewModel.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
using DynamicData.Aggregation;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a connection between a node input and a node output
|
||||
/// </summary>
|
||||
public class ConnectionViewModel : ReactiveObject
|
||||
{
|
||||
static ConnectionViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new ConnectionView(), typeof(IViewFor<ConnectionViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The network that contains this connection
|
||||
/// </summary>
|
||||
public NetworkViewModel Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The viewmodel of the node input that is on one end of the connection.
|
||||
/// </summary>
|
||||
public NodeInputViewModel Input { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The viewmodel of the node output that is on one end of the connection.
|
||||
/// </summary>
|
||||
public NodeOutputViewModel Output { get; }
|
||||
|
||||
#region CanBeRemovedByUser
|
||||
/// <summary>
|
||||
/// If false, the user cannot delete this connection. True by default.
|
||||
/// </summary>
|
||||
public bool CanBeRemovedByUser
|
||||
{
|
||||
get => _canBeRemovedByUser;
|
||||
set => this.RaiseAndSetIfChanged(ref _canBeRemovedByUser, value);
|
||||
}
|
||||
private bool _canBeRemovedByUser;
|
||||
#endregion
|
||||
|
||||
#region IsHighlighted
|
||||
/// <summary>
|
||||
/// If true, the connection is highlighted.
|
||||
/// </summary>
|
||||
public bool IsHighlighted
|
||||
{
|
||||
get => _isHighlighted;
|
||||
set => this.RaiseAndSetIfChanged(ref _isHighlighted, value);
|
||||
}
|
||||
private bool _isHighlighted;
|
||||
#endregion
|
||||
|
||||
#region IsInErrorState
|
||||
/// <summary>
|
||||
/// If true, the connection is displayed as being in an erroneous state.
|
||||
/// </summary>
|
||||
public bool IsInErrorState
|
||||
{
|
||||
get => _isInErrorState;
|
||||
set => this.RaiseAndSetIfChanged(ref _isInErrorState, value);
|
||||
}
|
||||
private bool _isInErrorState;
|
||||
#endregion
|
||||
|
||||
#region IsMarkedForDelete
|
||||
/// <summary>
|
||||
/// If true, the connection is displayed as being marked for deletion.
|
||||
/// </summary>
|
||||
public bool IsMarkedForDelete => _isMarkedForDelete.Value;
|
||||
private ObservableAsPropertyHelper<bool> _isMarkedForDelete;
|
||||
#endregion
|
||||
|
||||
public ConnectionViewModel(NetworkViewModel parent, NodeInputViewModel input, NodeOutputViewModel output)
|
||||
{
|
||||
Parent = parent;
|
||||
Input = input;
|
||||
Output = output;
|
||||
|
||||
this.WhenAnyValue(v => v.Parent.CutLine.IntersectingConnections)
|
||||
.Where(l => l != null)
|
||||
.Select(list => list.Connect().Filter(c => c == this).Count().Select(c => c > 0))
|
||||
.Switch()
|
||||
.ToProperty(this, vm => vm.IsMarkedForDelete, out _isMarkedForDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
intromat/NodeNetwork/ViewModels/CutLineViewModel.cs
Normal file
61
intromat/NodeNetwork/ViewModels/CutLineViewModel.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel class for the UI cutting line that is used to delete connections.
|
||||
/// </summary>
|
||||
public class CutLineViewModel : ReactiveObject
|
||||
{
|
||||
#region StartPoint
|
||||
/// <summary>
|
||||
/// The coordinates of the point at which the cutting line starts.
|
||||
/// </summary>
|
||||
public Point StartPoint
|
||||
{
|
||||
get => _startPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _startPoint, value);
|
||||
}
|
||||
private Point _startPoint;
|
||||
#endregion
|
||||
|
||||
#region EndPoint
|
||||
/// <summary>
|
||||
/// The coordinates of the point at which the cutting line ends.
|
||||
/// </summary>
|
||||
public Point EndPoint
|
||||
{
|
||||
get => _endPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _endPoint, value);
|
||||
}
|
||||
private Point _endPoint;
|
||||
#endregion
|
||||
|
||||
#region IsVisible
|
||||
/// <summary>
|
||||
/// If true, the cutting line is visible. If false, the cutting line is hidden.
|
||||
/// </summary>
|
||||
public bool IsVisible
|
||||
{
|
||||
get => _isVisible;
|
||||
set => this.RaiseAndSetIfChanged(ref _isVisible, value);
|
||||
}
|
||||
private bool _isVisible;
|
||||
#endregion
|
||||
|
||||
#region IntersectingConnections
|
||||
/// <summary>
|
||||
/// A list of connections that visually intersect with the cutting line.
|
||||
/// This list is driven by the view.
|
||||
/// </summary>
|
||||
public ISourceList<ConnectionViewModel> IntersectingConnections { get; } = new SourceList<ConnectionViewModel>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
255
intromat/NodeNetwork/ViewModels/Endpoint.cs
Normal file
255
intromat/NodeNetwork/ViewModels/Endpoint.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
using NodeNetwork.Utilities;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum type that indicates the position of the port in the endpoint
|
||||
/// </summary>
|
||||
public enum PortPosition
|
||||
{
|
||||
Left, Right
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum types that indicates the visibility behaviour of an endpoint
|
||||
/// </summary>
|
||||
public enum EndpointVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically decide whether or not to show this endpoint based on the collapse status of the node
|
||||
/// </summary>
|
||||
Auto,
|
||||
/// <summary>
|
||||
/// Always show this endpoint, even if the node is collapsed
|
||||
/// </summary>
|
||||
AlwaysVisible,
|
||||
/// <summary>
|
||||
/// Always hide this endpoint
|
||||
/// </summary>
|
||||
AlwaysHidden
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parent interface for the inputs/outputs of nodes between which connections can be made.
|
||||
/// </summary>
|
||||
public abstract class Endpoint : ReactiveObject
|
||||
{
|
||||
#region Parent
|
||||
/// <summary>
|
||||
/// The node that owns this endpoint
|
||||
/// </summary>
|
||||
public NodeViewModel Parent
|
||||
{
|
||||
get => _parent;
|
||||
internal set => this.RaiseAndSetIfChanged(ref _parent, value);
|
||||
}
|
||||
private NodeViewModel _parent;
|
||||
#endregion
|
||||
|
||||
#region Name
|
||||
/// <summary>
|
||||
/// The name of this endpoint.
|
||||
/// In the default view, this string is displayed in the node next to the port.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => this.RaiseAndSetIfChanged(ref _name, value);
|
||||
}
|
||||
private string _name = "";
|
||||
#endregion
|
||||
|
||||
#region Group
|
||||
|
||||
/// <summary>
|
||||
/// The group the end point belongs to. Can be null.
|
||||
/// </summary>
|
||||
public EndpointGroup Group
|
||||
{
|
||||
get => _group;
|
||||
set => this.RaiseAndSetIfChanged(ref _group, value);
|
||||
}
|
||||
private EndpointGroup _group;
|
||||
#endregion
|
||||
|
||||
#region Icon
|
||||
/// <summary>
|
||||
/// The icon displayed near the endpoint label
|
||||
/// If this is null, no icon is displayed.
|
||||
/// </summary>
|
||||
public IBitmap Icon
|
||||
{
|
||||
get => _icon;
|
||||
set => this.RaiseAndSetIfChanged(ref _icon, value);
|
||||
}
|
||||
private IBitmap _icon;
|
||||
#endregion
|
||||
|
||||
#region Editor
|
||||
/// <summary>
|
||||
/// The editor viewmodel associated with this endpoint.
|
||||
/// It can be used to configure the behaviour of this endpoint or provide a default value when there is no connection.
|
||||
/// The editor, if not null, will be displayed in the node, under the endpoint name next to the port.
|
||||
/// </summary>
|
||||
public NodeEndpointEditorViewModel Editor
|
||||
{
|
||||
get => _editor;
|
||||
set => this.RaiseAndSetIfChanged(ref _editor, value);
|
||||
}
|
||||
private NodeEndpointEditorViewModel _editor;
|
||||
#endregion
|
||||
|
||||
#region Port
|
||||
/// <summary>
|
||||
/// The viewmodel for the port of this endpoint. (the part the user can create connections from.)
|
||||
/// </summary>
|
||||
public PortViewModel Port
|
||||
{
|
||||
get => _port;
|
||||
set => this.RaiseAndSetIfChanged(ref _port, value);
|
||||
}
|
||||
private PortViewModel _port;
|
||||
#endregion
|
||||
|
||||
#region PortPosition
|
||||
/// <summary>
|
||||
/// Where should the port be positioned in the endpoint?
|
||||
/// </summary>
|
||||
public PortPosition PortPosition
|
||||
{
|
||||
get => _portPosition;
|
||||
set => this.RaiseAndSetIfChanged(ref _portPosition, value);
|
||||
}
|
||||
private PortPosition _portPosition;
|
||||
#endregion
|
||||
|
||||
#region Connections
|
||||
/// <summary>
|
||||
/// List of connections between this endpoint and other endpoints in the network.
|
||||
/// To add a new connection, do not add it here but instead add it to the Connections property in the network.
|
||||
/// </summary>
|
||||
public IObservableList<ConnectionViewModel> Connections { get; }
|
||||
#endregion
|
||||
|
||||
#region MaxConnections
|
||||
/// <summary>
|
||||
/// The maximum amount of connections this endpoint accepts.
|
||||
/// When Connections.Count == MaxConnections, the user cannot add more connections to this endpoint
|
||||
/// until a connection is removed.
|
||||
/// </summary>
|
||||
public int MaxConnections
|
||||
{
|
||||
get => _maxConnections;
|
||||
set => this.RaiseAndSetIfChanged(ref _maxConnections, value);
|
||||
}
|
||||
private int _maxConnections;
|
||||
#endregion
|
||||
|
||||
#region Visibility
|
||||
/// <summary>
|
||||
/// Visibility behaviour of this endpoint
|
||||
/// </summary>
|
||||
public EndpointVisibility Visibility
|
||||
{
|
||||
get => _visibility;
|
||||
set => this.RaiseAndSetIfChanged(ref _visibility, value);
|
||||
}
|
||||
private EndpointVisibility _visibility;
|
||||
#endregion
|
||||
|
||||
#region SortIndex
|
||||
/// <summary>
|
||||
/// Inputs and outputs are sorted by increasing values of SortIndex before being displayed.
|
||||
/// </summary>
|
||||
public int SortIndex
|
||||
{
|
||||
get => _sortIndex;
|
||||
set => this.RaiseAndSetIfChanged(ref _sortIndex, value);
|
||||
}
|
||||
private int _sortIndex;
|
||||
#endregion
|
||||
|
||||
protected Endpoint()
|
||||
{
|
||||
Port = new PortViewModel();
|
||||
Visibility = EndpointVisibility.Auto;
|
||||
|
||||
// Setup parent relationship with Port.
|
||||
this.WhenAnyValue(vm => vm.Port).PairWithPreviousValue().Subscribe(p =>
|
||||
{
|
||||
if (p.OldValue != null)
|
||||
{
|
||||
p.OldValue.Parent = null;
|
||||
}
|
||||
|
||||
if (p.NewValue != null)
|
||||
{
|
||||
p.NewValue.Parent = this;
|
||||
}
|
||||
});
|
||||
|
||||
// Setup Parent relationship with Editor.
|
||||
this.WhenAnyValue(vm => vm.Editor).PairWithPreviousValue().Subscribe(e =>
|
||||
{
|
||||
if (e.OldValue != null)
|
||||
{
|
||||
e.OldValue.Parent = null;
|
||||
}
|
||||
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
e.NewValue.Parent = this;
|
||||
}
|
||||
});
|
||||
|
||||
// Mirror the port if the endpoint is on the left instead of the right.
|
||||
this.WhenAnyValue(vm => vm.Port, vm => vm.PortPosition).Subscribe(_ =>
|
||||
{
|
||||
if (Port == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Port.IsMirrored = PortPosition == PortPosition.Left;
|
||||
});
|
||||
|
||||
// Setup a binding between the Connections list in the network and in this endpoint,
|
||||
// selecting only the connections where this endpoint is the input or output.
|
||||
|
||||
// We need the latest network connections list, but we want a null value when this endpoint is
|
||||
// removed from the node, or the node is removed from the network.
|
||||
var networkConnections = this.WhenAnyValue(
|
||||
vm => vm.Parent,
|
||||
vm => vm.Parent.Parent,
|
||||
vm => vm.Parent.Parent.Connections,
|
||||
(x, y, z) => Parent?.Parent?.Connections ?? new SourceList<ConnectionViewModel>())
|
||||
.Switch();
|
||||
|
||||
Connections = networkConnections
|
||||
.AutoRefresh(c => c.Input)
|
||||
.AutoRefresh(c => c.Output)
|
||||
.Filter(c => c.Input == this || c.Output == this)
|
||||
.AsObservableList();
|
||||
|
||||
// Setup bindings between port mouse events and connection creation.
|
||||
this.WhenAnyObservable(vm => vm.Port.ConnectionDragStarted).Subscribe(_ => CreatePendingConnection());
|
||||
this.WhenAnyObservable(vm => vm.Port.ConnectionPreviewActive).Subscribe(SetConnectionPreview);
|
||||
this.WhenAnyObservable(vm => vm.Port.ConnectionDragFinished).Subscribe(_ => FinishPendingConnection());
|
||||
}
|
||||
|
||||
protected abstract void CreatePendingConnection();
|
||||
protected abstract void SetConnectionPreview(bool previewActive);
|
||||
protected abstract void FinishPendingConnection();
|
||||
}
|
||||
}
|
||||
33
intromat/NodeNetwork/ViewModels/EndpointGroup.cs
Normal file
33
intromat/NodeNetwork/ViewModels/EndpointGroup.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
public class EndpointGroup : ReactiveObject
|
||||
{
|
||||
public EndpointGroup Parent { get; }
|
||||
|
||||
#region Name
|
||||
private string _name = "";
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => this.RaiseAndSetIfChanged(ref _name, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public EndpointGroup(EndpointGroup parent = null)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public EndpointGroup(string name, EndpointGroup parent = null)
|
||||
{
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
intromat/NodeNetwork/ViewModels/EndpointGroupViewModel.cs
Normal file
72
intromat/NodeNetwork/ViewModels/EndpointGroupViewModel.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
|
||||
using DynamicData;
|
||||
|
||||
using NodeNetwork.Views;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
public class EndpointGroupViewModel : ReactiveObject
|
||||
{
|
||||
static EndpointGroupViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new EndpointGroupView(), typeof(IViewFor<EndpointGroupViewModel>));
|
||||
}
|
||||
|
||||
#region VisibleInputs
|
||||
/// <summary>
|
||||
/// The list of inputs that is currently visible on this group.
|
||||
/// Some inputs may be hidden if the node is collapsed.
|
||||
/// </summary>
|
||||
public IObservableList<NodeInputViewModel> VisibleInputs { get; }
|
||||
#endregion
|
||||
|
||||
#region VisibleOutputs
|
||||
/// <summary>
|
||||
/// The list of outputs that is currently visible on this group.
|
||||
/// Some outputs may be hidden if the node is collapsed.
|
||||
/// </summary>
|
||||
public IObservableList<NodeOutputViewModel> VisibleOutputs { get; }
|
||||
#endregion
|
||||
|
||||
#region Group
|
||||
/// <summary>
|
||||
/// The endpoint group wrapping the name and the parent group of this group.
|
||||
/// </summary>
|
||||
public EndpointGroup Group { get; }
|
||||
#endregion
|
||||
|
||||
#region Children
|
||||
/// <summary>
|
||||
/// The list of nested endpoint groups.
|
||||
/// </summary>
|
||||
public ReadOnlyObservableCollection<EndpointGroupViewModel> Children => _children;
|
||||
private readonly ReadOnlyObservableCollection<EndpointGroupViewModel> _children;
|
||||
#endregion
|
||||
|
||||
public EndpointGroupViewModel(
|
||||
EndpointGroup group,
|
||||
IObservable<IChangeSet<NodeInputViewModel>> allInputs,
|
||||
IObservable<IChangeSet<NodeOutputViewModel>> allOutputs,
|
||||
IObservableCache<Node<EndpointGroup, EndpointGroup>, EndpointGroup> children,
|
||||
EndpointGroupViewModelFactory endpointGroupViewModelFactory)
|
||||
{
|
||||
Group = group;
|
||||
VisibleInputs = allInputs.Filter(e => e.Group == group).AsObservableList();
|
||||
VisibleOutputs = allOutputs.Filter(e => e.Group == group).AsObservableList();
|
||||
children
|
||||
.Connect()
|
||||
.Transform(n => endpointGroupViewModelFactory(n.Key, allInputs, allOutputs, n.Children, endpointGroupViewModelFactory))
|
||||
.Bind(out _children)
|
||||
.Subscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
using DynamicData;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// The factory method to create endpoint view models. Used in NodeViewModel.
|
||||
/// </summary>
|
||||
/// <param name="group">The endpoint group this view model wraps.</param>
|
||||
/// <param name="allInputs">All inputs of the group.</param>
|
||||
/// <param name="allOutputs">All outputs of the group.</param>
|
||||
/// <param name="children">Nested endpoint groups.</param>
|
||||
/// <param name="endpointGroupViewModelFactory">The factory method used to create the nested endpoint group view models.</param>
|
||||
/// <returns>The view model for the endpoint group.</returns>
|
||||
public delegate EndpointGroupViewModel EndpointGroupViewModelFactory(
|
||||
EndpointGroup group,
|
||||
IObservable<IChangeSet<NodeInputViewModel>> allInputs,
|
||||
IObservable<IChangeSet<NodeOutputViewModel>> allOutputs,
|
||||
IObservableCache<Node<EndpointGroup, EndpointGroup>, EndpointGroup> children,
|
||||
EndpointGroupViewModelFactory endpointGroupViewModelFactory);
|
||||
}
|
||||
35
intromat/NodeNetwork/ViewModels/ErrorMessageViewModel.cs
Normal file
35
intromat/NodeNetwork/ViewModels/ErrorMessageViewModel.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// A viewmodel for a simple error message.
|
||||
/// </summary>
|
||||
public class ErrorMessageViewModel : ReactiveObject
|
||||
{
|
||||
static ErrorMessageViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new ErrorMessageView(), typeof(IViewFor<ErrorMessageViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The text to be displayed that explains the error.
|
||||
/// </summary>
|
||||
public string Message { get; }
|
||||
|
||||
public ErrorMessageViewModel(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
430
intromat/NodeNetwork/ViewModels/NetworkViewModel.cs
Normal file
430
intromat/NodeNetwork/ViewModels/NetworkViewModel.cs
Normal file
@@ -0,0 +1,430 @@
|
||||
using NodeNetwork.Views;
|
||||
using NodeNetwork.Utilities;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Reactive.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using DynamicData;
|
||||
using DynamicData.Alias;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// The viewmodel for node networks.
|
||||
/// </summary>
|
||||
public class NetworkViewModel : ReactiveObject
|
||||
{
|
||||
static NetworkViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new NetworkView(), typeof(IViewFor<NetworkViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region Nodes
|
||||
/// <summary>
|
||||
/// The list of nodes in this network.
|
||||
/// </summary>
|
||||
public ISourceList<NodeViewModel> Nodes { get; } = new SourceList<NodeViewModel>();
|
||||
#endregion
|
||||
|
||||
#region SelectedNodes
|
||||
/// <summary>
|
||||
/// A list of nodes that are currently selected in the UI.
|
||||
/// The contents of this list is equal to the nodes in Nodes where the Selected property is true.
|
||||
/// </summary>
|
||||
public IObservableList<NodeViewModel> SelectedNodes { get; }
|
||||
#endregion
|
||||
|
||||
#region Connections
|
||||
/// <summary>
|
||||
/// The list of connections in this network.
|
||||
/// </summary>
|
||||
public ISourceList<ConnectionViewModel> Connections { get; } = new SourceList<ConnectionViewModel>();
|
||||
#endregion
|
||||
|
||||
#region PendingConnection
|
||||
/// <summary>
|
||||
/// The connection that is currently being build by the user.
|
||||
/// This connection is visually displayed in the UI, but is not an actual functional connection.
|
||||
/// This is used when the user drags from an endpoint to create a new connection.
|
||||
/// </summary>
|
||||
public PendingConnectionViewModel PendingConnection
|
||||
{
|
||||
get => _pendingConnection;
|
||||
set => this.RaiseAndSetIfChanged(ref _pendingConnection, value);
|
||||
}
|
||||
private PendingConnectionViewModel _pendingConnection;
|
||||
|
||||
public Action OnPendingConnectionDropped { get; set; }
|
||||
#endregion
|
||||
|
||||
#region PendingNode
|
||||
/// <summary>
|
||||
/// The viewmodel of the node that is not part of the network, but is displayed as a node that can be added.
|
||||
/// This property is used to display a new node when the user drags a node viewmodel over the network view.
|
||||
/// </summary>
|
||||
public NodeViewModel PendingNode
|
||||
{
|
||||
get => _pendingNode;
|
||||
set => this.RaiseAndSetIfChanged(ref _pendingNode, value);
|
||||
}
|
||||
private NodeViewModel _pendingNode;
|
||||
#endregion
|
||||
|
||||
#region ConnectionFactory
|
||||
/// <summary>
|
||||
/// The function that is used to create connection viewmodels when the user creates connections in the network view.
|
||||
/// By default, this function creates a ConnectionViewModel.
|
||||
/// </summary>
|
||||
public Func<NodeInputViewModel, NodeOutputViewModel, ConnectionViewModel> ConnectionFactory
|
||||
{
|
||||
get => _connectionFactory;
|
||||
set => this.RaiseAndSetIfChanged(ref _connectionFactory, value);
|
||||
}
|
||||
private Func<NodeInputViewModel, NodeOutputViewModel, ConnectionViewModel> _connectionFactory;
|
||||
#endregion
|
||||
|
||||
#region Validator
|
||||
/// <summary>
|
||||
/// Function that is used to check if the network is valid or not.
|
||||
/// To run the validation, use the UpdateValidation command.
|
||||
/// </summary>
|
||||
public Func<NetworkViewModel, NetworkValidationResult> Validator
|
||||
{
|
||||
get => _validator;
|
||||
set => this.RaiseAndSetIfChanged(ref _validator, value);
|
||||
}
|
||||
private Func<NetworkViewModel, NetworkValidationResult> _validator;
|
||||
#endregion
|
||||
|
||||
#region LatestValidation
|
||||
//Using ObservableAsPropertyHelper would be better, but causes problems with ReactiveCommand where
|
||||
//the value of the property is updated only after the subscribers to the command are run.
|
||||
|
||||
/// <summary>
|
||||
/// The validation of the current state of the network.
|
||||
/// This property is automatically updated when UpdateValidation runs.
|
||||
/// </summary>
|
||||
public NetworkValidationResult LatestValidation
|
||||
{
|
||||
get => _latestValidation;
|
||||
private set => this.RaiseAndSetIfChanged(ref _latestValidation, value);
|
||||
}
|
||||
private NetworkValidationResult _latestValidation;
|
||||
#endregion
|
||||
|
||||
#region Validation
|
||||
/// <summary>
|
||||
/// Observable that produces the latest NetworkValidationResult every time the network is validated.
|
||||
/// </summary>
|
||||
public IObservable<NetworkValidationResult> Validation { get; }
|
||||
#endregion
|
||||
|
||||
#region IsReadOnly
|
||||
/// <summary>
|
||||
/// If true, the network and its contents (nodes, connections, input/output editors, ...) cannot be modified by the user.
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => _isReadOnly;
|
||||
set => this.RaiseAndSetIfChanged(ref _isReadOnly, value);
|
||||
}
|
||||
private bool _isReadOnly;
|
||||
#endregion
|
||||
|
||||
#region CutLine
|
||||
/// <summary>
|
||||
/// The viewmodel of the cutline used in this network view.
|
||||
/// </summary>
|
||||
public CutLineViewModel CutLine { get; } = new CutLineViewModel();
|
||||
#endregion
|
||||
|
||||
#region ZoomFactor
|
||||
/// <summary>
|
||||
/// Scale of the view. Larger means more zoomed in. Default value is 1.
|
||||
/// </summary>
|
||||
public double ZoomFactor
|
||||
{
|
||||
get => _zoomFactor;
|
||||
set => this.RaiseAndSetIfChanged(ref _zoomFactor, value);
|
||||
}
|
||||
|
||||
private double _zoomFactor = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum zoom level used in this network view. Default value is 2.5.
|
||||
/// </summary>
|
||||
public double MaxZoomLevel
|
||||
{
|
||||
get => _maxZoomLevel;
|
||||
set => this.RaiseAndSetIfChanged(ref _maxZoomLevel, value);
|
||||
}
|
||||
|
||||
private double _maxZoomLevel = 2.5;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum zoom level used in this network view. Default value is 0.15.
|
||||
/// </summary>
|
||||
public double MinZoomLevel
|
||||
{
|
||||
get => _minZoomLevel;
|
||||
set => this.RaiseAndSetIfChanged(ref _minZoomLevel, value);
|
||||
}
|
||||
|
||||
private double _minZoomLevel = 0.15;
|
||||
|
||||
/// <summary>
|
||||
/// The drag offset of the initial view position used in this network view. Default value is (0, 0).
|
||||
/// </summary>
|
||||
public Point DragOffset
|
||||
{
|
||||
get => _dragOffset;
|
||||
set => this.RaiseAndSetIfChanged(ref _dragOffset, value);
|
||||
}
|
||||
|
||||
private Point _dragOffset = new Point(0, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region SelectionRectangle
|
||||
/// <summary>
|
||||
/// The viewmodel for the selection rectangle used in this network view.
|
||||
/// </summary>
|
||||
public SelectionRectangleViewModel SelectionRectangle { get; } = new SelectionRectangleViewModel();
|
||||
#endregion
|
||||
|
||||
#region NetworkChanged
|
||||
/// <summary>
|
||||
/// This observable pushes a notification when a connection was added to/removed from the network,
|
||||
/// and the relevant endpoints have been updated.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observing the Connections list directly will trigger the same notifications,
|
||||
/// but before the endpoints have had a chance to update and so they may be in an invalid state.
|
||||
/// </remarks>
|
||||
public IObservable<Unit> ConnectionsUpdated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This observable pushes a notification whenever any functional changes are made to the network.
|
||||
/// Purely esthetical changes, such as the collapsing of nodes, do not trigger this observable.
|
||||
/// </summary>
|
||||
public IObservable<Unit> NetworkChanged { get; }
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
/// <summary>
|
||||
/// Deletes the nodes in SelectedNodes that are user-removable.
|
||||
/// </summary>
|
||||
public ReactiveCommand<Unit, Unit> DeleteSelectedNodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Runs the Validator function and stores the result in LatestValidation.
|
||||
/// </summary>
|
||||
public ReactiveCommand<Unit, NetworkValidationResult> UpdateValidation { get; }
|
||||
#endregion
|
||||
|
||||
public NetworkViewModel()
|
||||
{
|
||||
// Setup parent relationship in nodes.
|
||||
Nodes.Connect().ActOnEveryObject(
|
||||
addedNode => addedNode.Parent = this,
|
||||
removedNode => removedNode.Parent = null
|
||||
);
|
||||
|
||||
// SelectedNodes is a derived collection of all nodes with IsSelected = true.
|
||||
SelectedNodes = Nodes.Connect()
|
||||
.AutoRefresh(node => node.IsSelected)
|
||||
.Filter(node => node.IsSelected)
|
||||
.AsObservableList();
|
||||
|
||||
// When DeleteSelectedNodes is invoked, remove all nodes that are user-removable and selected.
|
||||
DeleteSelectedNodes = ReactiveCommand.Create(OnDeleteSelectedNodes);
|
||||
|
||||
// When a node is removed, delete any connections from/to that node.
|
||||
Nodes.Preview().OnItemRemoved(removedNode =>
|
||||
{
|
||||
Connections.RemoveMany(removedNode.Inputs.Items.SelectMany(o => o.Connections.Items));
|
||||
Connections.RemoveMany(removedNode.Outputs.Items.SelectMany(o => o.Connections.Items));
|
||||
|
||||
bool pendingConnectionInvalid = PendingConnection?.Input?.Parent == removedNode ||
|
||||
PendingConnection?.Output?.Parent == removedNode;
|
||||
if (pendingConnectionInvalid)
|
||||
{
|
||||
RemovePendingConnection();
|
||||
}
|
||||
}).Subscribe();
|
||||
|
||||
// If, while dragging a pending connection, the mouse is released over the canvas, then cancel the connection.
|
||||
OnPendingConnectionDropped = RemovePendingConnection;
|
||||
|
||||
// When the list of nodes is reset, remove any connections whose input/output node was removed.
|
||||
/*Nodes.ShouldReset.Subscribe(_ =>
|
||||
{
|
||||
// Create a hashset with all nodes for O(1) search
|
||||
HashSet<NodeViewModel> nodeSet = new HashSet<NodeViewModel>(Nodes);
|
||||
|
||||
var connections = Connections.Items.ToArray();
|
||||
for (var i = connections.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!nodeSet.Contains(connections[i].Input.Parent) || !nodeSet.Contains(connections[i].Output.Parent))
|
||||
{
|
||||
Connections.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
var pendingConnInputNode = PendingConnection?.Input?.Parent;
|
||||
var pendingConnOutputNode = PendingConnection?.Output?.Parent;
|
||||
bool pendingConnectionInvalid = (pendingConnInputNode != null && !nodeSet.Contains(pendingConnInputNode)) ||
|
||||
(pendingConnOutputNode != null && !nodeSet.Contains(pendingConnOutputNode));
|
||||
if (pendingConnectionInvalid)
|
||||
{
|
||||
RemovePendingConnection();
|
||||
}
|
||||
});*/
|
||||
|
||||
// Setup a default ConnectionFactory that will be used to create connections.
|
||||
ConnectionFactory = (input, output) => new ConnectionViewModel(this, input, output);
|
||||
|
||||
// Setup a default network validator that always returns valid.
|
||||
Validator = _ => new NetworkValidationResult(true, true, null);
|
||||
|
||||
// Setup the validation command.
|
||||
UpdateValidation = ReactiveCommand.Create(() => {
|
||||
var result = Validator(this);
|
||||
LatestValidation = result;
|
||||
return result;
|
||||
});
|
||||
|
||||
// Setup Validation observable
|
||||
var onValidationPropertyUpdate = this.WhenAnyValue(vm => vm.LatestValidation).Publish().RefCount();
|
||||
Validation = Observable.Defer(() => onValidationPropertyUpdate.StartWith(LatestValidation));
|
||||
|
||||
// When a connection or node changes, validate the network.
|
||||
// Zip is used because when a connection is removed, it will trigger a change in both the input and the output and we want to combine these.
|
||||
|
||||
var a = Nodes.Connect()
|
||||
.AutoRefreshOnObservable(node => node.Inputs.Connect())
|
||||
.SelectMany(node => node.Inputs.Items)
|
||||
.AutoRefreshOnObservable(input => input.Connections.Connect())
|
||||
.SelectMany(input => input.Connections.Items);
|
||||
|
||||
var b = Nodes.Connect()
|
||||
.AutoRefreshOnObservable(node => node.Outputs.Connect())
|
||||
.SelectMany(node => node.Outputs.Items)
|
||||
.AutoRefreshOnObservable(output => output.Connections.Connect())
|
||||
.SelectMany(output => output.Connections.Items);
|
||||
|
||||
ConnectionsUpdated = Observable.Zip(
|
||||
a,
|
||||
b,
|
||||
(x, y) => Unit.Default
|
||||
).Publish().RefCount();
|
||||
ConnectionsUpdated.InvokeCommand(UpdateValidation);
|
||||
Nodes.Connect().Select((IChangeSet<NodeViewModel> n) => Unit.Default).InvokeCommand(UpdateValidation);
|
||||
|
||||
// Push a network change notification when a functional network change occurs.
|
||||
// These include:
|
||||
// - Nodes are added/removed
|
||||
// - Connections are added/removed
|
||||
// - Endpoint editors change
|
||||
// - Network validation changes
|
||||
NetworkChanged = Observable.Merge(
|
||||
Observable.Select(Nodes.Connect(), _ => Unit.Default),
|
||||
Observable.Select(Nodes.Connect().MergeMany(node => node.Inputs.Connect()), _ => Unit.Default),
|
||||
Observable.Select(Nodes.Connect().MergeMany(node => node.Outputs.Connect()), _ => Unit.Default),
|
||||
ConnectionsUpdated,
|
||||
OnEditorChanged(),
|
||||
Validation.Select(_ => Unit.Default)
|
||||
).Publish().RefCount();
|
||||
}
|
||||
|
||||
protected virtual void OnDeleteSelectedNodes()
|
||||
{
|
||||
Nodes.RemoveMany(SelectedNodes.Items.Where(n => n.CanBeRemovedByUser).ToArray());
|
||||
}
|
||||
|
||||
private IObservable<Unit> OnEditorChanged()
|
||||
{
|
||||
return Observable.Merge(
|
||||
Nodes.Connect().MergeMany(n =>
|
||||
n.Inputs.Connect().MergeMany(i =>
|
||||
// Use WhenAnyObservable because Editor can change.
|
||||
i.WhenAnyObservable(vm => vm.Editor.Changed)
|
||||
)
|
||||
).Select(_ => Unit.Default),
|
||||
Nodes.Connect().MergeMany(n =>
|
||||
n.Outputs.Connect().MergeMany(o =>
|
||||
o.WhenAnyObservable(vm => vm.Editor.Changed)
|
||||
)
|
||||
).Select(_ => Unit.Default)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears SelectedNodes, setting the IsSelected property of all the nodes to false.
|
||||
/// </summary>
|
||||
public void ClearSelection()
|
||||
{
|
||||
foreach (NodeViewModel node in SelectedNodes.Items)
|
||||
{
|
||||
node.IsSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a cut in the CutLine viewmodel.
|
||||
/// </summary>
|
||||
public void StartCut()
|
||||
{
|
||||
CutLine.IsVisible = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the current cut in the CutLine viewmodel and applies the changes.
|
||||
/// </summary>
|
||||
public virtual void FinishCut()
|
||||
{
|
||||
Connections.RemoveMany(CutLine.IntersectingConnections.Items);
|
||||
CutLine.IsVisible = false;
|
||||
CutLine.IntersectingConnections.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets PendingConnection to null.
|
||||
/// </summary>
|
||||
public void RemovePendingConnection()
|
||||
{
|
||||
PendingConnection = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a selection in RectangleSelection
|
||||
/// </summary>
|
||||
public void StartRectangleSelection()
|
||||
{
|
||||
ClearSelection();
|
||||
SelectionRectangle.IsVisible = true;
|
||||
SelectionRectangle.IntersectingNodes.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the current selection in RectangleSelection and applies the changes.
|
||||
/// </summary>
|
||||
public void FinishRectangleSelection()
|
||||
{
|
||||
SelectionRectangle.IsVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// The viewmodel for the editor component that is displayed next to a node endpoint.
|
||||
/// </summary>
|
||||
public class NodeEndpointEditorViewModel : ReactiveObject
|
||||
{
|
||||
static NodeEndpointEditorViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new NodeEndpointEditorView(), typeof(IViewFor<NodeEndpointEditorViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region Parent
|
||||
/// <summary>
|
||||
/// The endpoint that has this object as its editor.
|
||||
/// </summary>
|
||||
public Endpoint Parent
|
||||
{
|
||||
get => _parent;
|
||||
internal set => this.RaiseAndSetIfChanged(ref _parent, value);
|
||||
}
|
||||
private Endpoint _parent;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
203
intromat/NodeNetwork/ViewModels/NodeInputViewModel.cs
Normal file
203
intromat/NodeNetwork/ViewModels/NodeInputViewModel.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel class for inputs on a node.
|
||||
/// Inputs are endpoints that can only be connected to outputs.
|
||||
/// </summary>
|
||||
public class NodeInputViewModel : Endpoint
|
||||
{
|
||||
static NodeInputViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new NodeInputView(), typeof(IViewFor<NodeInputViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region IsEditorVisible
|
||||
/// <summary>
|
||||
/// If true, the editor is visible. Otherwise, the editor is hidden.
|
||||
/// See HideEditorIfConnected.
|
||||
/// </summary>
|
||||
public bool IsEditorVisible => _isEditorVisible.Value;
|
||||
private ObservableAsPropertyHelper<bool> _isEditorVisible;
|
||||
#endregion
|
||||
|
||||
#region HideEditorIfConnected
|
||||
/// <summary>
|
||||
/// If true, the editor of this input will be hidden if Connection is not null.
|
||||
/// This makes sense if the editor is used to provide a value when no connection is present.
|
||||
/// </summary>
|
||||
public bool HideEditorIfConnected
|
||||
{
|
||||
get => _hideEditorIfConnected;
|
||||
set => this.RaiseAndSetIfChanged(ref _hideEditorIfConnected, value);
|
||||
}
|
||||
private bool _hideEditorIfConnected;
|
||||
#endregion
|
||||
|
||||
#region ConnectionValidator
|
||||
/// <summary>
|
||||
/// This function is called when a new connection with this input is pending.
|
||||
/// It decides whether or not the pending connection is valid.
|
||||
/// If the validation result says the pending connection is invalid,
|
||||
/// then the user will not be able to add the connection to the network.
|
||||
/// </summary>
|
||||
public Func<PendingConnectionViewModel, ConnectionValidationResult> ConnectionValidator
|
||||
{
|
||||
get => _connectionValidator;
|
||||
set => this.RaiseAndSetIfChanged(ref _connectionValidator, value);
|
||||
}
|
||||
private Func<PendingConnectionViewModel, ConnectionValidationResult> _connectionValidator;
|
||||
#endregion
|
||||
|
||||
public NodeInputViewModel()
|
||||
{
|
||||
this.HideEditorIfConnected = true;
|
||||
|
||||
this.Connections.CountChanged.Select(c => c == 0).StartWith(true)
|
||||
.CombineLatest(this.WhenAnyValue(vm => vm.HideEditorIfConnected), (noConnections, hideEditorIfConnected) => !hideEditorIfConnected || noConnections)
|
||||
.ToProperty(this, vm => vm.IsEditorVisible, out _isEditorVisible);
|
||||
|
||||
this.ConnectionValidator = con => new ConnectionValidationResult(true, null);
|
||||
|
||||
this.MaxConnections = 1;
|
||||
this.PortPosition = PortPosition.Left;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the pending connection in the network to a new connection with this endpoint as the input.
|
||||
/// If this input already is connected, and MaxConnections == 1,
|
||||
/// then the connection is replaced by a pending connection without this endpoint.
|
||||
/// If the connection would be invalid, no pending connection is made.
|
||||
/// Called when the user clicks on this endpoint.
|
||||
/// </summary>
|
||||
protected override void CreatePendingConnection()
|
||||
{
|
||||
NetworkViewModel network = Parent?.Parent;
|
||||
if (network == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PendingConnectionViewModel pendingConnection;
|
||||
if (MaxConnections == 1 && Connections.Items.Any())
|
||||
{
|
||||
var conn = Connections.Items.First();
|
||||
pendingConnection = new PendingConnectionViewModel(network)
|
||||
{
|
||||
Output = conn.Output,
|
||||
OutputIsLocked = true,
|
||||
LooseEndPoint = Port.CenterPoint
|
||||
};
|
||||
network.Connections.Remove(conn);
|
||||
}
|
||||
else if(Connections.Count < MaxConnections)
|
||||
{
|
||||
pendingConnection = new PendingConnectionViewModel(network) { Input = this, InputIsLocked = true, LooseEndPoint = Port.CenterPoint };
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pendingConnection.LooseEndPoint = Port.CenterPoint;
|
||||
network.PendingConnection = pendingConnection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets this endpoint as the input of the pending connection and updates its validation.
|
||||
/// Called when the user drags and holds a pending connection over this endpoint.
|
||||
/// </summary>
|
||||
/// <param name="previewActive">
|
||||
/// True to set this endpoint as the output of the pending connection.
|
||||
/// To remove this endpoint from the pending connection, set this to false.
|
||||
/// </param>
|
||||
protected override void SetConnectionPreview(bool previewActive)
|
||||
{
|
||||
PendingConnectionViewModel pendingCon = Parent.Parent.PendingConnection;
|
||||
if (pendingCon.Input != null && (pendingCon.Input != this || pendingCon.InputIsLocked))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (previewActive)
|
||||
{
|
||||
pendingCon.Input = this;
|
||||
pendingCon.Validation = ConnectionValidator(pendingCon);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingCon.Input = null;
|
||||
pendingCon.Validation = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new connection in the network based on the pending connection and this endpoint as the input.
|
||||
/// If the connection would be invalid, no connection is made.
|
||||
/// The pending connection is deleted.
|
||||
/// Called when the user drags and releases a pending connection over this endpoint.
|
||||
/// </summary>
|
||||
protected override void FinishPendingConnection()
|
||||
{
|
||||
NetworkViewModel network = Parent?.Parent;
|
||||
if (network == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (network.PendingConnection.Input == this && !network.PendingConnection.InputIsLocked)
|
||||
{
|
||||
//Only allow drag from output to input, not input to input
|
||||
if (network.PendingConnection.Input.Parent != network.PendingConnection.Output.Parent)
|
||||
{
|
||||
//Dont allow connections between an input and an output on the same node
|
||||
if (network.PendingConnection.Validation.IsValid)
|
||||
{
|
||||
//Don't allow a new connection if max amount of connections has been reached and we
|
||||
//can't automatically remove one.
|
||||
if (Connections.Count < MaxConnections || MaxConnections == 1)
|
||||
{
|
||||
//Connection is valid
|
||||
bool canCreateConnection = true;
|
||||
|
||||
if (MaxConnections == Connections.Count && MaxConnections == 1)
|
||||
{
|
||||
//Remove the connection to this input
|
||||
network.Connections.Remove(Connections.Items.First());
|
||||
}
|
||||
else if (MaxConnections > 2)
|
||||
{
|
||||
// Make sure connection does not exist already.
|
||||
if (network.Connections.Items.Any(con => con.Output == network.PendingConnection.Output && con.Input == this))
|
||||
{
|
||||
canCreateConnection = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (canCreateConnection)
|
||||
{
|
||||
//Add new connection
|
||||
network.Connections.Add(network.ConnectionFactory(this, network.PendingConnection.Output));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
network.RemovePendingConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
124
intromat/NodeNetwork/ViewModels/NodeOutputViewModel.cs
Normal file
124
intromat/NodeNetwork/ViewModels/NodeOutputViewModel.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
using NodeNetwork.Utilities;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel class for outputs on a node.
|
||||
/// Outputs are endpoints that can only be connected to inputs.
|
||||
/// </summary>
|
||||
public class NodeOutputViewModel : Endpoint
|
||||
{
|
||||
static NodeOutputViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new NodeOutputView(), typeof(IViewFor<NodeOutputViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
public NodeOutputViewModel()
|
||||
{
|
||||
MaxConnections = Int32.MaxValue;
|
||||
this.PortPosition = PortPosition.Right;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the pending connection in the network to a new connection with this endpoint as the output.
|
||||
/// If the connection would be invalid, no pending connection is made.
|
||||
/// Called when the user clicks on this endpoint.
|
||||
/// </summary>
|
||||
protected override void CreatePendingConnection()
|
||||
{
|
||||
NetworkViewModel network = Parent?.Parent;
|
||||
if (network == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Connections.Count >= MaxConnections)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
network.PendingConnection = new PendingConnectionViewModel(network) { Output = this, OutputIsLocked = true, LooseEndPoint = Port.CenterPoint };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets this endpoint as the output of the pending connection and updates its validation.
|
||||
/// Called when the user drags and holds a pending connection over this endpoint.
|
||||
/// </summary>
|
||||
/// <param name="previewActive">
|
||||
/// True to set this endpoint as the output of the pending connection.
|
||||
/// To remove this endpoint from the pending connection, set this to false.
|
||||
/// </param>
|
||||
protected override void SetConnectionPreview(bool previewActive)
|
||||
{
|
||||
PendingConnectionViewModel pendingCon = Parent.Parent.PendingConnection;
|
||||
if (pendingCon.Output != null && (pendingCon.Output != this || pendingCon.OutputIsLocked))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (previewActive)
|
||||
{
|
||||
pendingCon.Output = this;
|
||||
pendingCon.Validation = pendingCon.Input.ConnectionValidator(pendingCon);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingCon.Output = null;
|
||||
pendingCon.Validation = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new connection in the network based on the pending connection and this endpoint as the output.
|
||||
/// If the connection would be invalid, no connection is made.
|
||||
/// The pending connection is deleted.
|
||||
/// Called when the user drags and releases a pending connection over this endpoint.
|
||||
/// </summary>
|
||||
protected override void FinishPendingConnection()
|
||||
{
|
||||
NetworkViewModel network = Parent?.Parent;
|
||||
if (network == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (network.PendingConnection.Output == this && !network.PendingConnection.OutputIsLocked)
|
||||
{
|
||||
//Only allow drag from output to input, not input to input
|
||||
if (network.PendingConnection.Input.Parent != network.PendingConnection.Output.Parent)
|
||||
{
|
||||
//Dont allow connections between an input and an output on the same node
|
||||
if (network.PendingConnection.Validation.IsValid)
|
||||
{
|
||||
//Connection is valid
|
||||
if (MaxConnections > Connections.Count)
|
||||
{
|
||||
//MaxConnections hasn't been reached yet.
|
||||
if (!network.Connections.Items.Any(con => con.Output == this && con.Input == network.PendingConnection.Input))
|
||||
{
|
||||
//Connection does not exist already
|
||||
network.Connections.Add(network.ConnectionFactory(network.PendingConnection.Input, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
network.RemovePendingConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
352
intromat/NodeNetwork/ViewModels/NodeViewModel.cs
Normal file
352
intromat/NodeNetwork/ViewModels/NodeViewModel.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
public enum ResizeOrientation
|
||||
{
|
||||
None,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
HorizontalAndVertical
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Viewmodel class for the nodes in the network
|
||||
/// </summary>
|
||||
public class NodeViewModel : ReactiveObject
|
||||
{
|
||||
static NodeViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new NodeView(), typeof(IViewFor<NodeViewModel>));
|
||||
Locator.CurrentMutable.RegisterPlatformBitmapLoader();
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region Parent
|
||||
/// <summary>
|
||||
/// The network that contains this node
|
||||
/// </summary>
|
||||
public NetworkViewModel Parent
|
||||
{
|
||||
get => _parent;
|
||||
internal set => this.RaiseAndSetIfChanged(ref _parent, value);
|
||||
}
|
||||
private NetworkViewModel _parent;
|
||||
#endregion
|
||||
|
||||
#region Name
|
||||
/// <summary>
|
||||
/// The name of the node.
|
||||
/// In the default view, this string is displayed at the top of the node.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => this.RaiseAndSetIfChanged(ref _name, value);
|
||||
}
|
||||
private string _name;
|
||||
#endregion
|
||||
|
||||
#region HeaderIcon
|
||||
/// <summary>
|
||||
/// The icon displayed in the header of the node.
|
||||
/// If this is null, no icon is displayed.
|
||||
/// In the default view, this icon is displayed at the top of the node.
|
||||
/// </summary>
|
||||
public IBitmap HeaderIcon
|
||||
{
|
||||
get => _headerIcon;
|
||||
set => this.RaiseAndSetIfChanged(ref _headerIcon, value);
|
||||
}
|
||||
private IBitmap _headerIcon;
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
/// <summary>
|
||||
/// The list of inputs on this node.
|
||||
/// </summary>
|
||||
public ISourceList<NodeInputViewModel> Inputs { get; } = new SourceList<NodeInputViewModel>();
|
||||
#endregion
|
||||
|
||||
#region Outputs
|
||||
/// <summary>
|
||||
/// The list of outputs on this node.
|
||||
/// </summary>
|
||||
public ISourceList<NodeOutputViewModel> Outputs { get; } = new SourceList<NodeOutputViewModel>();
|
||||
#endregion
|
||||
|
||||
#region VisibleInputs
|
||||
/// <summary>
|
||||
/// The list of inputs that is currently visible on this node.
|
||||
/// Some inputs may be hidden if the node is collapsed.
|
||||
/// </summary>
|
||||
public IObservableList<NodeInputViewModel> VisibleInputs { get; }
|
||||
#endregion
|
||||
|
||||
#region VisibleOutputs
|
||||
/// <summary>
|
||||
/// The list of outputs that is currently visible on this node.
|
||||
/// Some outputs may be hidden if the node is collapsed.
|
||||
/// </summary>
|
||||
public IObservableList<NodeOutputViewModel> VisibleOutputs { get; }
|
||||
#endregion
|
||||
|
||||
#region VisibleEndpointGroups
|
||||
/// <summary>
|
||||
/// The list of endpoint groups that is currently visible on this node.
|
||||
/// Some groups may be hidden if the node is collapsed.
|
||||
/// </summary>
|
||||
public ReadOnlyObservableCollection<EndpointGroupViewModel> VisibleEndpointGroups { get; }
|
||||
#endregion
|
||||
|
||||
#region EndpointGroupViewModelFactory
|
||||
/// <summary>
|
||||
/// The function that is used to create endpoint group view models.
|
||||
/// By default, this function creates a EndpointGroupViewModel.
|
||||
/// </summary>
|
||||
public EndpointGroupViewModelFactory EndpointGroupViewModelFactory
|
||||
{
|
||||
get => _endpointGroupViewModelFactory;
|
||||
set => this.RaiseAndSetIfChanged(ref _endpointGroupViewModelFactory, value);
|
||||
}
|
||||
private EndpointGroupViewModelFactory _endpointGroupViewModelFactory;
|
||||
#endregion
|
||||
|
||||
#region IsSelected
|
||||
/// <summary>
|
||||
/// If true, this node is currently selected in the UI.
|
||||
/// </summary>
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set => this.RaiseAndSetIfChanged(ref _isSelected, value);
|
||||
}
|
||||
private bool _isSelected;
|
||||
#endregion
|
||||
|
||||
#region IsCollapsed
|
||||
/// <summary>
|
||||
/// If true, this node is currently collapsed.
|
||||
/// If the node is collapsed, some parts of the node are hidden to provide a more compact view.
|
||||
/// </summary>
|
||||
public bool IsCollapsed
|
||||
{
|
||||
get => _isCollapsed;
|
||||
set => this.RaiseAndSetIfChanged(ref _isCollapsed, value);
|
||||
}
|
||||
private bool _isCollapsed;
|
||||
#endregion
|
||||
|
||||
#region CanBeRemovedByUser
|
||||
/// <summary>
|
||||
/// If true, the user can delete this node from the network in the UI.
|
||||
/// True by default.
|
||||
/// </summary>
|
||||
public bool CanBeRemovedByUser
|
||||
{
|
||||
get => _canBeRemovedByUser;
|
||||
set => this.RaiseAndSetIfChanged(ref _canBeRemovedByUser, value);
|
||||
}
|
||||
private bool _canBeRemovedByUser;
|
||||
#endregion
|
||||
|
||||
#region Position
|
||||
/// <summary>
|
||||
/// The position of this node in the network.
|
||||
/// </summary>
|
||||
public Point Position
|
||||
{
|
||||
get => _position;
|
||||
set => this.RaiseAndSetIfChanged(ref _position, value);
|
||||
}
|
||||
private Point _position;
|
||||
#endregion
|
||||
|
||||
#region Size
|
||||
/// <summary>
|
||||
/// The rendered size of this node.
|
||||
/// </summary>
|
||||
public Size Size
|
||||
{
|
||||
get => _size;
|
||||
internal set => this.RaiseAndSetIfChanged(ref _size, value);
|
||||
}
|
||||
private Size _size;
|
||||
#endregion
|
||||
|
||||
#region Resizable
|
||||
/// <summary>
|
||||
/// On which axes can the user resize the node?
|
||||
/// </summary>
|
||||
public ResizeOrientation Resizable
|
||||
{
|
||||
get => _resizable;
|
||||
set => this.RaiseAndSetIfChanged(ref _resizable, value);
|
||||
}
|
||||
private ResizeOrientation _resizable;
|
||||
#endregion
|
||||
|
||||
public NodeViewModel()
|
||||
{
|
||||
// Setup a default EndpointGroupViewModelFactory that will be used to create endpoint groups.
|
||||
EndpointGroupViewModelFactory = (group, allInputs, allOutputs, children, factory) => new EndpointGroupViewModel(group, allInputs, allOutputs, children, factory);
|
||||
|
||||
this.Name = "Untitled";
|
||||
this.CanBeRemovedByUser = true;
|
||||
this.Resizable = ResizeOrientation.Horizontal;
|
||||
|
||||
// Setup parent relationship with inputs.
|
||||
Inputs.Connect().ActOnEveryObject(
|
||||
addedInput => addedInput.Parent = this,
|
||||
removedInput => removedInput.Parent = null
|
||||
);
|
||||
|
||||
// Setup parent relationship with outputs.
|
||||
Outputs.Connect().ActOnEveryObject(
|
||||
addedOutput => addedOutput.Parent = this,
|
||||
removedOutput => removedOutput.Parent = null
|
||||
);
|
||||
|
||||
// When an input is removed, delete any connection to/from that input
|
||||
Inputs.Preview().OnItemRemoved(removedInput =>
|
||||
{
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Connections.RemoveMany(removedInput.Connections.Items);
|
||||
|
||||
bool pendingConnectionInvalid = Parent.PendingConnection?.Input == removedInput;
|
||||
if (pendingConnectionInvalid)
|
||||
{
|
||||
Parent.RemovePendingConnection();
|
||||
}
|
||||
}
|
||||
}).Subscribe();
|
||||
|
||||
// Same for outputs.
|
||||
Outputs.Preview().OnItemRemoved(removedOutput =>
|
||||
{
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Connections.RemoveMany(removedOutput.Connections.Items);
|
||||
|
||||
bool pendingConnectionInvalid = Parent.PendingConnection?.Output == removedOutput;
|
||||
if (pendingConnectionInvalid)
|
||||
{
|
||||
Parent.RemovePendingConnection();
|
||||
}
|
||||
}
|
||||
}).Subscribe();
|
||||
|
||||
// If collapsed, hide inputs without connections, otherwise show all.
|
||||
var onCollapseChange = this.WhenAnyValue(vm => vm.IsCollapsed).Publish();
|
||||
onCollapseChange.Connect();
|
||||
|
||||
var visibilityFilteredInputs = Inputs.Connect()
|
||||
.AutoRefreshOnObservable(_ => onCollapseChange)
|
||||
.AutoRefresh(vm => vm.Visibility)
|
||||
.AutoRefresh(vm => vm.Group)
|
||||
.Filter(i =>
|
||||
{
|
||||
if (IsCollapsed)
|
||||
{
|
||||
return i.Visibility == EndpointVisibility.AlwaysVisible || (i.Visibility == EndpointVisibility.Auto && i.Connections.Items.Any());
|
||||
}
|
||||
|
||||
return i.Visibility != EndpointVisibility.AlwaysHidden;
|
||||
});
|
||||
VisibleInputs = visibilityFilteredInputs
|
||||
.Filter(i => i.Group == null)
|
||||
.Sort(Comparer<NodeInputViewModel>.Create((i1, i2) => i1.SortIndex.CompareTo(i2.SortIndex)),
|
||||
resort: Inputs.Connect().WhenValueChanged(i => i.SortIndex).Select(_ => Unit.Default))
|
||||
.AsObservableList();
|
||||
|
||||
// Same for outputs.
|
||||
var visibilityFilteredOutputs = Outputs.Connect()
|
||||
.AutoRefreshOnObservable(_ => onCollapseChange)
|
||||
.AutoRefresh(vm => vm.Visibility)
|
||||
.AutoRefresh(vm => vm.Group)
|
||||
.Filter(o =>
|
||||
{
|
||||
if (IsCollapsed)
|
||||
{
|
||||
return o.Visibility == EndpointVisibility.AlwaysVisible || (o.Visibility == EndpointVisibility.Auto && o.Connections.Items.Any());
|
||||
}
|
||||
|
||||
return o.Visibility != EndpointVisibility.AlwaysHidden;
|
||||
});
|
||||
VisibleOutputs = visibilityFilteredOutputs
|
||||
.Filter(o => o.Group == null)
|
||||
.Sort(Comparer<NodeOutputViewModel>.Create((o1, o2) => o1.SortIndex.CompareTo(o2.SortIndex)),
|
||||
resort: Outputs.Connect().WhenValueChanged(o => o.SortIndex).Select(_ => Unit.Default))
|
||||
.AsObservableList();
|
||||
|
||||
// Get all the groups, also the empty ones.
|
||||
var allInputGroups
|
||||
= visibilityFilteredInputs
|
||||
.TransformMany(GetAllGroupsInHierarchy)
|
||||
.AddKey(g => g);
|
||||
|
||||
var allOutputGroups
|
||||
= visibilityFilteredOutputs
|
||||
.TransformMany(GetAllGroupsInHierarchy)
|
||||
.AddKey(g => g);
|
||||
|
||||
IEnumerable<EndpointGroup> GetAllGroupsInHierarchy(Endpoint endpoint)
|
||||
{
|
||||
var group = endpoint.Group;
|
||||
while (group != null)
|
||||
{
|
||||
yield return group;
|
||||
group = group.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge needs AddKey first, otherwise removal of endpoints leads to confusion.
|
||||
var allGroups
|
||||
= allInputGroups
|
||||
.Merge(allOutputGroups)
|
||||
.DistinctValues(g => g);
|
||||
|
||||
// Used as temporary root for TransformToTree.
|
||||
var root = new EndpointGroup();
|
||||
|
||||
// To react on change of the EndpointGroupViewModelFactory.
|
||||
var onEndpointGroupViewModelFactoryChange = this.WhenAnyValue(vm => vm.EndpointGroupViewModelFactory);
|
||||
|
||||
allGroups
|
||||
.TransformToTree(group => group.Parent ?? root)
|
||||
.AutoRefreshOnObservable(_ => onEndpointGroupViewModelFactoryChange)
|
||||
.Transform(n => EndpointGroupViewModelFactory(n.Key,
|
||||
visibilityFilteredInputs,
|
||||
visibilityFilteredOutputs,
|
||||
n.Children,
|
||||
EndpointGroupViewModelFactory))
|
||||
.Bind(out var groups)
|
||||
.Subscribe();
|
||||
|
||||
VisibleEndpointGroups = groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
133
intromat/NodeNetwork/ViewModels/PendingConnectionViewModel.cs
Normal file
133
intromat/NodeNetwork/ViewModels/PendingConnectionViewModel.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel for a connection that is currently being build by the user.
|
||||
/// </summary>
|
||||
public class PendingConnectionViewModel : ReactiveObject
|
||||
{
|
||||
static PendingConnectionViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new PendingConnectionView(), typeof(IViewFor<PendingConnectionViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region Parent
|
||||
/// <summary>
|
||||
/// The network viewmodel that this connection is being build in.
|
||||
/// </summary>
|
||||
public NetworkViewModel Parent { get; }
|
||||
#endregion
|
||||
|
||||
#region Input
|
||||
/// <summary>
|
||||
/// The node input viewmodel, if any, that is on one side of the connection.
|
||||
/// Can be null.
|
||||
/// </summary>
|
||||
public NodeInputViewModel Input
|
||||
{
|
||||
get => _input;
|
||||
set => this.RaiseAndSetIfChanged(ref _input, value);
|
||||
}
|
||||
private NodeInputViewModel _input;
|
||||
#endregion
|
||||
|
||||
#region InputIsLocked
|
||||
/// <summary>
|
||||
/// If true, Input will not be changed.
|
||||
/// This is used to mark Input as the starting point of the pending connection.
|
||||
/// </summary>
|
||||
public bool InputIsLocked
|
||||
{
|
||||
get => _inputIsLocked;
|
||||
set => this.RaiseAndSetIfChanged(ref _inputIsLocked, value);
|
||||
}
|
||||
private bool _inputIsLocked;
|
||||
#endregion
|
||||
|
||||
#region Output
|
||||
/// <summary>
|
||||
/// The node output viewmodel, if any, that is on one side of the connection.
|
||||
/// Can be null.
|
||||
/// </summary>
|
||||
public NodeOutputViewModel Output
|
||||
{
|
||||
get => _output;
|
||||
set => this.RaiseAndSetIfChanged(ref _output, value);
|
||||
}
|
||||
private NodeOutputViewModel _output;
|
||||
#endregion
|
||||
|
||||
#region OutputIsLocked
|
||||
/// <summary>
|
||||
/// If true, Output will not be changed.
|
||||
/// This is used to mark Output as the starting point of the pending connection.
|
||||
/// </summary>
|
||||
public bool OutputIsLocked
|
||||
{
|
||||
get => _outputIsLocked;
|
||||
set => this.RaiseAndSetIfChanged(ref _outputIsLocked, value);
|
||||
}
|
||||
private bool _outputIsLocked;
|
||||
#endregion
|
||||
|
||||
#region LooseEndPoint
|
||||
/// <summary>
|
||||
/// The current coordinates of the point where the pending connection ends on the loose side.
|
||||
/// This value is used when the Input or Output is null.
|
||||
/// </summary>
|
||||
public Point LooseEndPoint
|
||||
{
|
||||
get => _looseEndPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _looseEndPoint, value);
|
||||
}
|
||||
private Point _looseEndPoint;
|
||||
#endregion
|
||||
|
||||
#region BoundingBox
|
||||
/// <summary>
|
||||
/// The rectangle that contains the entire connection view.
|
||||
/// </summary>
|
||||
public Rect BoundingBox => _boundingBox.Value;
|
||||
private readonly ObservableAsPropertyHelper<Rect> _boundingBox;
|
||||
#endregion
|
||||
|
||||
#region Validation
|
||||
/// <summary>
|
||||
/// The validation of the current connection state.
|
||||
/// If invalid, the connection will be displayed as such and an error message will be displayed.
|
||||
/// The pending connection must be valid before it can be added to the network as a real connection.
|
||||
/// </summary>
|
||||
public ConnectionValidationResult Validation
|
||||
{
|
||||
get => _validation;
|
||||
set => this.RaiseAndSetIfChanged(ref _validation, value);
|
||||
}
|
||||
private ConnectionValidationResult _validation;
|
||||
#endregion
|
||||
|
||||
public PendingConnectionViewModel(NetworkViewModel parent)
|
||||
{
|
||||
Parent = parent;
|
||||
this.WhenAnyValue(vm => vm.Input, vm => vm.Output, vm => vm.LooseEndPoint)
|
||||
.Select(_ =>
|
||||
{
|
||||
Point p1 = Output?.Port.CenterPoint ?? LooseEndPoint;
|
||||
Point p2 = Input?.Port.CenterPoint ?? LooseEndPoint;
|
||||
return new Rect(p1, p2);
|
||||
}).ToProperty(this, vm => vm.BoundingBox, out _boundingBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
168
intromat/NodeNetwork/ViewModels/PortViewModel.cs
Normal file
168
intromat/NodeNetwork/ViewModels/PortViewModel.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using NodeNetwork.Views;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel class for the UI part of an endpoint that is used to create connections.
|
||||
/// </summary>
|
||||
public class PortViewModel : ReactiveObject
|
||||
{
|
||||
static PortViewModel()
|
||||
{
|
||||
NNViewRegistrar.AddRegistration(() => new PortView(), typeof(IViewFor<PortViewModel>));
|
||||
}
|
||||
|
||||
#region Logger
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#endregion
|
||||
|
||||
#region Parent
|
||||
/// <summary>
|
||||
/// The Endpoint that owns this port.
|
||||
/// </summary>
|
||||
public Endpoint Parent
|
||||
{
|
||||
get => _parent;
|
||||
set => this.RaiseAndSetIfChanged(ref _parent, value);
|
||||
}
|
||||
private Endpoint _parent;
|
||||
#endregion
|
||||
|
||||
#region CenterPoint
|
||||
/// <summary>
|
||||
/// The coordinates, relative to the network, of the center of this port.
|
||||
/// Used to draw connections.
|
||||
/// </summary>
|
||||
public Point CenterPoint
|
||||
{
|
||||
get => _centerPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _centerPoint, value);
|
||||
}
|
||||
private Point _centerPoint;
|
||||
#endregion
|
||||
|
||||
#region IsMirrored
|
||||
/// <summary>
|
||||
/// If true, the view for this viewmodel will be horizontally mirrored.
|
||||
/// </summary>
|
||||
public bool IsMirrored
|
||||
{
|
||||
get => _isMirrored;
|
||||
set => this.RaiseAndSetIfChanged(ref _isMirrored, value);
|
||||
}
|
||||
private bool _isMirrored;
|
||||
#endregion
|
||||
|
||||
#region IsVisible
|
||||
/// <summary>
|
||||
/// If true, this port is visible. If false, this port is hidden.
|
||||
/// True by default.
|
||||
/// </summary>
|
||||
public bool IsVisible
|
||||
{
|
||||
get => _isVisible;
|
||||
set => this.RaiseAndSetIfChanged(ref _isVisible, value);
|
||||
}
|
||||
private bool _isVisible;
|
||||
#endregion
|
||||
|
||||
#region IsHighlighted
|
||||
/// <summary>
|
||||
/// If true, this port is highlighted.
|
||||
/// This could be, for example, because the mouse is hovering over the port.
|
||||
/// </summary>
|
||||
public bool IsHighlighted
|
||||
{
|
||||
get => _isHighlighted;
|
||||
set => this.RaiseAndSetIfChanged(ref _isHighlighted, value);
|
||||
}
|
||||
private bool _isHighlighted;
|
||||
#endregion
|
||||
|
||||
#region IsInErrorMode
|
||||
/// <summary>
|
||||
/// If true, the port will visually indicate there is an error with this port.
|
||||
/// In the default view this is used to indicate a pending connection validation error.
|
||||
/// </summary>
|
||||
public bool IsInErrorMode
|
||||
{
|
||||
get => _isInErrorMode;
|
||||
set => this.RaiseAndSetIfChanged(ref _isInErrorMode, value);
|
||||
}
|
||||
private bool _isInErrorMode;
|
||||
#endregion
|
||||
|
||||
#region ConnectionDragStarted
|
||||
/// <summary>
|
||||
/// Observable that fires when the user starts a new pending connection from this port.
|
||||
/// </summary>
|
||||
public IObservable<Unit> ConnectionDragStarted => _connectionDragStarted;
|
||||
private readonly Subject<Unit> _connectionDragStarted = new Subject<Unit>();
|
||||
#endregion
|
||||
|
||||
#region ConnectionPreview
|
||||
/// <summary>
|
||||
/// Fires when a pending connection is dragged over this port.
|
||||
/// </summary>
|
||||
public IObservable<bool> ConnectionPreviewActive => _connectionPreviewActive;
|
||||
private readonly Subject<bool> _connectionPreviewActive = new Subject<bool>();
|
||||
#endregion
|
||||
|
||||
#region ConnectionDragFinished
|
||||
/// <summary>
|
||||
/// Fires when the user drops the pending connection on this port.
|
||||
/// </summary>
|
||||
public IObservable<Unit> ConnectionDragFinished => _connectionDragFinished;
|
||||
private readonly Subject<Unit> _connectionDragFinished = new Subject<Unit>();
|
||||
#endregion
|
||||
|
||||
public PortViewModel()
|
||||
{
|
||||
IsVisible = true;
|
||||
}
|
||||
|
||||
public virtual void OnDragFromPort()
|
||||
{
|
||||
_connectionDragStarted.OnNext(Unit.Default);
|
||||
}
|
||||
|
||||
public void OnPortEnter()
|
||||
{
|
||||
IsHighlighted = true;
|
||||
|
||||
PendingConnectionViewModel pendingConnection = Parent.Parent?.Parent?.PendingConnection;
|
||||
if (pendingConnection != null && pendingConnection.Input != Parent && pendingConnection.Output != Parent)
|
||||
{
|
||||
_connectionPreviewActive.OnNext(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPortLeave()
|
||||
{
|
||||
IsHighlighted = false;
|
||||
|
||||
PendingConnectionViewModel pendingConnection = Parent.Parent?.Parent?.PendingConnection;
|
||||
if (pendingConnection != null)
|
||||
{
|
||||
_connectionPreviewActive.OnNext(false);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnDropOnPort()
|
||||
{
|
||||
if (Parent?.Parent?.Parent?.PendingConnection != null)
|
||||
{
|
||||
_connectionDragFinished.OnNext(Unit.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Viewmodel for the view that is used to select nodes by dragging a rectangle around them.
|
||||
/// </summary>
|
||||
public class SelectionRectangleViewModel : ReactiveObject
|
||||
{
|
||||
#region StartPoint
|
||||
/// <summary>
|
||||
/// The coordinates of the first corner of the rectangle (where the user clicked down).
|
||||
/// </summary>
|
||||
public Point StartPoint
|
||||
{
|
||||
get => _startPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _startPoint, value);
|
||||
}
|
||||
private Point _startPoint;
|
||||
#endregion
|
||||
|
||||
#region EndPoint
|
||||
/// <summary>
|
||||
/// The coordinates of the second corner of the rectangle.
|
||||
/// </summary>
|
||||
public Point EndPoint
|
||||
{
|
||||
get => _endPoint;
|
||||
set => this.RaiseAndSetIfChanged(ref _endPoint, value);
|
||||
}
|
||||
private Point _endPoint;
|
||||
#endregion
|
||||
|
||||
#region Rectangle
|
||||
/// <summary>
|
||||
/// The Rect object formed by StartPoint and EndPoint.
|
||||
/// </summary>
|
||||
public Rect Rectangle => _rectangle.Value;
|
||||
private readonly ObservableAsPropertyHelper<Rect> _rectangle;
|
||||
#endregion
|
||||
|
||||
#region IsVisible
|
||||
/// <summary>
|
||||
/// If true, the selection rectangle view is visible.
|
||||
/// </summary>
|
||||
public bool IsVisible
|
||||
{
|
||||
get => _isVisible;
|
||||
set => this.RaiseAndSetIfChanged(ref _isVisible, value);
|
||||
}
|
||||
private bool _isVisible;
|
||||
#endregion
|
||||
|
||||
#region IntersectingNodes
|
||||
/// <summary>
|
||||
/// List of nodes visually intersecting or contained in the rectangle.
|
||||
/// This list is driven by the view.
|
||||
/// </summary>
|
||||
public ISourceList<NodeViewModel> IntersectingNodes { get; } = new SourceList<NodeViewModel>();
|
||||
#endregion
|
||||
|
||||
public SelectionRectangleViewModel()
|
||||
{
|
||||
this.WhenAnyValue(vm => vm.StartPoint, vm => vm.EndPoint)
|
||||
.Select(_ => new Rect(StartPoint, EndPoint))
|
||||
.ToProperty(this, vm => vm.Rectangle, out _rectangle);
|
||||
|
||||
IntersectingNodes.Connect().ActOnEveryObject(node => node.IsSelected = true, node => node.IsSelected = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
228
intromat/NodeNetwork/Views/ConnectionView.cs
Normal file
228
intromat/NodeNetwork/Views/ConnectionView.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplateVisualState(Name = HighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonHighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = ErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = MarkedForDeleteState, GroupName = MarkedForDeleteVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NotMarkedForDeleteState, GroupName = MarkedForDeleteVisualStatesGroup)]
|
||||
public class ConnectionView : Control, IViewFor<ConnectionViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(ConnectionViewModel), typeof(ConnectionView), new PropertyMetadata(null));
|
||||
|
||||
public ConnectionViewModel ViewModel
|
||||
{
|
||||
get => (ConnectionViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ConnectionViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region States
|
||||
#region HighlightStates
|
||||
public const string HighlightVisualStatesGroup = "HighlightStates";
|
||||
public const string HighlightedState = "Highlighted";
|
||||
public const string NonHighlightedState = "NonHighlighted";
|
||||
#endregion
|
||||
|
||||
#region ErrorStates
|
||||
public const string ErrorVisualStatesGroup = "ErrorStates";
|
||||
public const string ErrorState = "Error";
|
||||
public const string NonErrorState = "NoError";
|
||||
#endregion
|
||||
|
||||
#region ErrorStates
|
||||
public const string MarkedForDeleteVisualStatesGroup = "MarkedForDeleteStates";
|
||||
public const string MarkedForDeleteState = "Marked";
|
||||
public const string NotMarkedForDeleteState = "NotMarked";
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region RegularBrush
|
||||
public Brush RegularBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(RegularBrushProperty);
|
||||
set => this.SetValue(RegularBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty RegularBrushProperty = DependencyProperty.Register(nameof(RegularBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region ErrorBrush
|
||||
public Brush ErrorBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ErrorBrushProperty);
|
||||
set => this.SetValue(ErrorBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ErrorBrushProperty = DependencyProperty.Register(nameof(ErrorBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region HighlightBrush
|
||||
public Brush HighlightBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(HighlightBrushProperty);
|
||||
set => this.SetValue(HighlightBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register(nameof(HighlightBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region MarkedForDeleteBrush
|
||||
public Brush MarkedForDeleteBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(MarkedForDeleteBrushProperty);
|
||||
set => this.SetValue(MarkedForDeleteBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty MarkedForDeleteBrushProperty =
|
||||
DependencyProperty.Register(nameof(MarkedForDeleteBrush), typeof(Brush), typeof(ConnectionView), new PropertyMetadata());
|
||||
#endregion
|
||||
|
||||
#region Geometry
|
||||
public Geometry Geometry
|
||||
{
|
||||
get => (Geometry)this.GetValue(GeometryProperty);
|
||||
private set => this.SetValue(GeometryProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty GeometryProperty = DependencyProperty.Register(nameof(Geometry), typeof(Geometry), typeof(ConnectionView));
|
||||
#endregion
|
||||
|
||||
public ConnectionView()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(ConnectionView);
|
||||
|
||||
SetupPathData();
|
||||
SetupBrushesBinding();
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
VisualStateManager.GoToState(this, NonHighlightedState, false);
|
||||
VisualStateManager.GoToState(this, NonErrorState, false);
|
||||
VisualStateManager.GoToState(this, NotMarkedForDeleteState, false);
|
||||
}
|
||||
|
||||
private void SetupPathData()
|
||||
{
|
||||
this.WhenActivated(d => d(
|
||||
this.WhenAny(
|
||||
v => v.ViewModel.Input.Port.CenterPoint,
|
||||
v => v.ViewModel.Input.PortPosition,
|
||||
v => v.ViewModel.Output.Port.CenterPoint,
|
||||
v => v.ViewModel.Output.PortPosition,
|
||||
(a, b, c, e) => (a, b, c, e))
|
||||
.Select(_
|
||||
=> BuildSmoothBezier(
|
||||
ViewModel.Input.Port.CenterPoint,
|
||||
ViewModel.Input.PortPosition,
|
||||
ViewModel.Output.Port.CenterPoint,
|
||||
ViewModel.Output.PortPosition))
|
||||
.BindTo(this, v => v.Geometry)
|
||||
));
|
||||
}
|
||||
|
||||
private void SetupBrushesBinding()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.WhenAnyValue(v => v.ViewModel.IsHighlighted).Subscribe(isHighlighted =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isHighlighted ? HighlightedState : NonHighlightedState, true);
|
||||
}).DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel.IsInErrorState).Subscribe(isInErrorState =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isInErrorState ? ErrorState : NonErrorState, true);
|
||||
}).DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel.IsMarkedForDelete).Subscribe(isMarkedForDelete =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isMarkedForDelete ? MarkedForDeleteState : NotMarkedForDeleteState, true);
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, PortPosition startPosition, Point endPoint, PortPosition endPosition)
|
||||
{
|
||||
Vector startGradient = ToGradient(startPosition);
|
||||
Vector endGradient = ToGradient(endPosition);
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, PortPosition startPosition, Point endPoint)
|
||||
{
|
||||
Vector startGradient = ToGradient(startPosition);
|
||||
Vector endGradient = -startGradient;
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
public static PathGeometry BuildSmoothBezier(Point startPoint, Point endPoint, PortPosition endPosition)
|
||||
{
|
||||
Vector endGradient = ToGradient(endPosition);
|
||||
Vector startGradient = -endGradient;
|
||||
|
||||
return BuildSmoothBezier(startPoint, startGradient, endPoint, endGradient);
|
||||
}
|
||||
|
||||
private static Vector ToGradient(PortPosition portPosition)
|
||||
{
|
||||
switch (portPosition)
|
||||
{
|
||||
case PortPosition.Left:
|
||||
return new Vector(-1, 0);
|
||||
case PortPosition.Right:
|
||||
return new Vector(1, 0);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private const double MinGradient = 10;
|
||||
private const double WidthScaling = 5;
|
||||
|
||||
private static PathGeometry BuildSmoothBezier(Point startPoint, Vector startGradient, Point endPoint, Vector endGradient)
|
||||
{
|
||||
double width = endPoint.X - startPoint.X;
|
||||
|
||||
var gradientScale = Math.Sqrt(Math.Abs(width) * WidthScaling + MinGradient * MinGradient);
|
||||
|
||||
Point startGradientPoint = startPoint + startGradient * gradientScale;
|
||||
Point endGradientPoint = endPoint + endGradient * gradientScale;
|
||||
|
||||
Point midPoint = new Point((startGradientPoint.X + endGradientPoint.X) / 2d, (startPoint.Y + endPoint.Y) / 2d);
|
||||
|
||||
PathFigure pathFigure = new PathFigure
|
||||
{
|
||||
StartPoint = startPoint,
|
||||
IsClosed = false,
|
||||
Segments =
|
||||
{
|
||||
new QuadraticBezierSegment(startGradientPoint, midPoint, true),
|
||||
new QuadraticBezierSegment(endGradientPoint, endPoint, true)
|
||||
}
|
||||
};
|
||||
|
||||
PathGeometry geom = new PathGeometry();
|
||||
geom.Figures.Add(pathFigure);
|
||||
|
||||
return geom;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/NodeNetwork/Views/Controls/ArrowToggleButton.xaml
Normal file
66
intromat/NodeNetwork/Views/Controls/ArrowToggleButton.xaml
Normal file
@@ -0,0 +1,66 @@
|
||||
<ToggleButton x:Class="NodeNetwork.Views.Controls.ArrowToggleButton"
|
||||
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:NodeNetwork.Views"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="30" d:DesignWidth="30" Name="button">
|
||||
<ToggleButton.Template>
|
||||
<ControlTemplate>
|
||||
<Viewbox StretchDirection="Both" Stretch="Uniform">
|
||||
<Grid Width="20" Height="20">
|
||||
<Path Width="20" Height="12" Stretch="Fill" Stroke="#333" Fill="Transparent" StrokeThickness="3" Data="M 0,0 L 10,9.5 L 20,0 ">
|
||||
<Path.Style>
|
||||
<Style TargetType="Path">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, ElementName=button}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="#555" Duration="0:0:0.1"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="#333" Duration="0:0:0.1"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Path.Style>
|
||||
</Path>
|
||||
<Grid.RenderTransform>
|
||||
<RotateTransform CenterX="10" CenterY="10"/>
|
||||
</Grid.RenderTransform>
|
||||
<Grid.Style>
|
||||
<Style TargetType="Grid">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, ElementName=button}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Grid.RenderTransform).(RotateTransform.Angle)" To="-90" Duration="0:0:0.1"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Grid.RenderTransform).(RotateTransform.Angle)" To="0" Duration="0:0:0.1"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Style>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</ControlTemplate>
|
||||
</ToggleButton.Template>
|
||||
</ToggleButton>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace NodeNetwork.Views.Controls
|
||||
{
|
||||
public partial class ArrowToggleButton : ToggleButton
|
||||
{
|
||||
public ArrowToggleButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
437
intromat/NodeNetwork/Views/Controls/DragCanvas.cs
Normal file
437
intromat/NodeNetwork/Views/Controls/DragCanvas.cs
Normal file
@@ -0,0 +1,437 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace NodeNetwork.Views.Controls
|
||||
{
|
||||
public class DragCanvas : Canvas
|
||||
{
|
||||
#region Position
|
||||
public static readonly DependencyProperty DragOffsetProperty = DependencyProperty.Register(nameof(DragOffset),
|
||||
typeof(Point), typeof(DragCanvas), new PropertyMetadata(new Point(), DragOffsetChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current canvas drag offset.
|
||||
/// </summary>
|
||||
public Point DragOffset
|
||||
{
|
||||
get => (Point)GetValue(DragOffsetProperty);
|
||||
set => SetValue(DragOffsetProperty, value);
|
||||
}
|
||||
|
||||
private static void DragOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var canvas = (DragCanvas)d;
|
||||
if (e.NewValue is Point position)
|
||||
{
|
||||
canvas.ApplyDragToChildren(position.X - canvas._previousDragOffset.X, position.Y - canvas._previousDragOffset.Y);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dragging
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the user clicks and moves the canvas, starting a drag
|
||||
/// </summary>
|
||||
/// <param name="sender">The dragcanvas that triggered this event</param>
|
||||
/// <param name="args">The mouseevent that triggered this event</param>
|
||||
public delegate void DragStartEventHandler(object sender, MouseEventArgs args);
|
||||
public event DragStartEventHandler DragStart;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the user drags the canvas
|
||||
/// </summary>
|
||||
/// <param name="sender">The dragcanvas that triggered this event</param>
|
||||
/// <param name="args">Contains the distance traveled since the last drag move or drag start event</param>
|
||||
public delegate void DragMoveEventHandler(object sender, DragMoveEventArgs args);
|
||||
public event DragMoveEventHandler DragMove;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the user releases the mouse and the drag stops.
|
||||
/// </summary>
|
||||
/// <param name="sender">The dragcanvas that triggered this event</param>
|
||||
/// <param name="args">Contains the total distance traveled</param>
|
||||
public delegate void DragEndEventHandler(object sender, DragMoveEventArgs args);
|
||||
public event DragEndEventHandler DragStop;
|
||||
|
||||
public bool IsDraggingEnabled { get; set; } = true;
|
||||
|
||||
#region StartDragGesture
|
||||
public static readonly DependencyProperty StartDragGestureProperty = DependencyProperty.Register(nameof(StartDragGesture),
|
||||
typeof(MouseGesture), typeof(DragCanvas), new PropertyMetadata(new MouseGesture(MouseAction.LeftClick)));
|
||||
|
||||
/// <summary>
|
||||
/// This mouse gesture starts a drag on the canvas. Left click by default.
|
||||
/// </summary>
|
||||
public MouseGesture StartDragGesture
|
||||
{
|
||||
get => (MouseGesture)GetValue(StartDragGestureProperty);
|
||||
set => SetValue(StartDragGestureProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Used when the mousebutton is down to check if the initial click was in this element.
|
||||
/// This is useful because we dont want to assume a drag operation when the user moves the mouse but originally clicked a different element
|
||||
/// </summary>
|
||||
private bool _userClickedThisElement;
|
||||
|
||||
/// <summary>
|
||||
/// Is a drag operation currently in progress?
|
||||
/// </summary>
|
||||
private bool _dragActive;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the mouse (screen co-ordinate) where the mouse was clicked down.
|
||||
/// </summary>
|
||||
private Point _originScreenCoordPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the mouse (screen co-ordinate) when the previous DragDelta event was fired
|
||||
/// </summary>
|
||||
private Point _previousMouseScreenPos;
|
||||
private Point _previousDragOffset;
|
||||
|
||||
/// <summary>
|
||||
/// This event puts the control into a state where it is ready for a drag operation.
|
||||
/// </summary>
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
if (IsDraggingEnabled && StartDragGesture.Matches(this, e))
|
||||
{
|
||||
_userClickedThisElement = true;
|
||||
|
||||
_previousMouseScreenPos = _originScreenCoordPosition = e.GetPosition(this);
|
||||
Focus();
|
||||
CaptureMouse(); //All mouse events will now be handled by the dragcanvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trigger a dragging event when the user moves the mouse while the left mouse button is pressed
|
||||
/// </summary>
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
if (_userClickedThisElement && !_dragActive)
|
||||
{
|
||||
_dragActive = true;
|
||||
DragStart?.Invoke(this, e);
|
||||
}
|
||||
|
||||
if (_dragActive)
|
||||
{
|
||||
Point curMouseScreenPos = e.GetPosition(this);
|
||||
|
||||
if (!curMouseScreenPos.Equals(_previousMouseScreenPos))
|
||||
{
|
||||
double xDelta = curMouseScreenPos.X - _previousMouseScreenPos.X;
|
||||
double yDelta = curMouseScreenPos.Y - _previousMouseScreenPos.Y;
|
||||
|
||||
var dragEvent = new DragMoveEventArgs(e, xDelta, yDelta);
|
||||
DragMove?.Invoke(this, dragEvent);
|
||||
|
||||
this.DragOffset = new Point(_previousDragOffset.X + xDelta, _previousDragOffset.Y + yDelta);
|
||||
|
||||
_previousMouseScreenPos = curMouseScreenPos;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop dragging when the user releases the mouse button
|
||||
/// </summary>
|
||||
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||
{
|
||||
_userClickedThisElement = false;
|
||||
ReleaseMouseCapture(); //Stop absorbing all mouse events
|
||||
|
||||
if (_dragActive)
|
||||
{
|
||||
_dragActive = false;
|
||||
|
||||
Point curMouseScreenPos = e.GetPosition(this);
|
||||
double xDelta = curMouseScreenPos.X - _originScreenCoordPosition.X;
|
||||
double yDelta = curMouseScreenPos.Y - _originScreenCoordPosition.Y;
|
||||
|
||||
DragStop?.Invoke(this, new DragMoveEventArgs(e, xDelta, yDelta));
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyDragToChildren(double deltaX, double deltaY)
|
||||
{
|
||||
foreach (UIElement cur in Children)
|
||||
{
|
||||
double prevLeft = Canvas.GetLeft(cur);
|
||||
if (Double.IsNaN(prevLeft))
|
||||
{
|
||||
prevLeft = 0;
|
||||
}
|
||||
|
||||
double prevTop = Canvas.GetTop(cur);
|
||||
if (Double.IsNaN(prevTop))
|
||||
{
|
||||
prevTop = 0;
|
||||
}
|
||||
|
||||
Canvas.SetLeft(cur, prevLeft + (deltaX));
|
||||
Canvas.SetTop(cur, prevTop + (deltaY));
|
||||
}
|
||||
|
||||
_previousDragOffset = new Point(_previousDragOffset.X + deltaX, _previousDragOffset.Y + deltaY);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Zoom
|
||||
public event EventHandler<ZoomEventArgs> Zoom;
|
||||
|
||||
private double _wheelOffset = 6;
|
||||
|
||||
#region ZoomFactor
|
||||
public static readonly DependencyProperty ZoomFactorProperty = DependencyProperty.Register(nameof(ZoomFactor),
|
||||
typeof(double), typeof(DragCanvas), new PropertyMetadata(1d, OnZoomFactorPropChanged, ZoomFactorValueCoerce));
|
||||
|
||||
public double ZoomFactor
|
||||
{
|
||||
get => (double)GetValue(ZoomFactorProperty);
|
||||
set => SetValue(ZoomFactorProperty, value);
|
||||
}
|
||||
private bool isUpdatingZoomFactor;
|
||||
|
||||
private static void OnZoomFactorPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
DragCanvas dc = (DragCanvas)d;
|
||||
if (!dc.isUpdatingZoomFactor)
|
||||
{
|
||||
dc.SetZoomImpl(new Point(dc.ActualWidth / 2, dc.ActualHeight / 2), (double)e.OldValue, (double)e.NewValue, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static object ZoomFactorValueCoerce(DependencyObject d, object baseValue)
|
||||
{
|
||||
if (baseValue is double doubleValue)
|
||||
{
|
||||
var canvas = (DragCanvas)d;
|
||||
if (doubleValue < canvas.MinZoomFactor)
|
||||
{
|
||||
return canvas.MinZoomFactor;
|
||||
}
|
||||
else if (doubleValue > canvas.MaxZoomFactor)
|
||||
{
|
||||
return canvas.MaxZoomFactor;
|
||||
}
|
||||
}
|
||||
|
||||
return baseValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MaxZoomFactor
|
||||
public static readonly DependencyProperty MaxZoomFactorProperty = DependencyProperty.Register(nameof(MaxZoomFactor),
|
||||
typeof(double), typeof(DragCanvas), new FrameworkPropertyMetadata(2.5d, MaxZoomFactorChanged));
|
||||
|
||||
public double MaxZoomFactor
|
||||
{
|
||||
get { return (double)GetValue(MaxZoomFactorProperty); }
|
||||
set { SetValue(MaxZoomFactorProperty, value); }
|
||||
}
|
||||
|
||||
private static void MaxZoomFactorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var doubleValue = (double)e.NewValue;
|
||||
if (double.IsNaN(doubleValue) || double.IsInfinity(doubleValue) || doubleValue <= 0)
|
||||
{
|
||||
throw new ArgumentException("MaxZoomFactor can not be NaN, Infinity or less than zero");
|
||||
}
|
||||
|
||||
var canvas = (DragCanvas)d;
|
||||
var binding = BindingOperations.GetBindingExpression(canvas, ZoomFactorProperty);
|
||||
binding?.UpdateTarget();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MinZoomFactor
|
||||
public static readonly DependencyProperty MinZoomFactorProperty = DependencyProperty.Register(nameof(MinZoomFactor),
|
||||
typeof(double), typeof(DragCanvas), new FrameworkPropertyMetadata(0.15d, MinZoomFactorChanged));
|
||||
|
||||
public double MinZoomFactor
|
||||
{
|
||||
get { return (double)GetValue(MinZoomFactorProperty); }
|
||||
set { SetValue(MinZoomFactorProperty, value); }
|
||||
}
|
||||
|
||||
private static void MinZoomFactorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var doubleValue = (double)e.NewValue;
|
||||
if (double.IsNaN(doubleValue) || double.IsInfinity(doubleValue) || doubleValue <= 0)
|
||||
{
|
||||
throw new ArgumentException("MinZoomFactor can not be NaN, Infinity or less than zero");
|
||||
}
|
||||
|
||||
var canvas = (DragCanvas)d;
|
||||
var binding = BindingOperations.GetBindingExpression(canvas, ZoomFactorProperty);
|
||||
binding?.UpdateTarget();
|
||||
}
|
||||
#endregion
|
||||
|
||||
private Rect ZoomView(Rect curView, double curZoom, double newZoom, Point relZoomPoint) //curView in content space, relZoomPoint is relative to view space
|
||||
{
|
||||
double zoomModifier = curZoom / newZoom;
|
||||
Size newSize = new Size(curView.Width * zoomModifier, curView.Height * zoomModifier);
|
||||
|
||||
Point zoomCenter = new Point(curView.X + (curView.Width * relZoomPoint.X), curView.Y + (curView.Height * relZoomPoint.Y));
|
||||
double newX = zoomCenter.X - (relZoomPoint.X * newSize.Width);
|
||||
double newY = zoomCenter.Y - (relZoomPoint.Y * newSize.Height);
|
||||
Point newPos = new Point(newX, newY);
|
||||
|
||||
return new Rect(newPos, newSize);
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
//Calculate new scaling factor
|
||||
var wheelOffset = _wheelOffset + (e.Delta / 120);
|
||||
double newScale = Math.Log(1 + (wheelOffset / 10d)) * 2d;
|
||||
if (newScale < MinZoomFactor)
|
||||
{
|
||||
newScale = MinZoomFactor;
|
||||
}
|
||||
else if (newScale > MaxZoomFactor)
|
||||
{
|
||||
newScale = MaxZoomFactor;
|
||||
}
|
||||
|
||||
Point zoomCenter = e.GetPosition(this);
|
||||
SetZoom(zoomCenter, newScale, e);
|
||||
}
|
||||
|
||||
public void SetZoom(Point zoomCenter, double newScale, MouseEventArgs parentEvent)
|
||||
{
|
||||
SetZoomImpl(zoomCenter, ZoomFactor, newScale, parentEvent);
|
||||
isUpdatingZoomFactor = true;
|
||||
ZoomFactor = newScale;
|
||||
isUpdatingZoomFactor = false;
|
||||
}
|
||||
|
||||
private void SetZoomImpl(Point zoomCenter, double oldScale, double newScale, MouseEventArgs parentEvent)
|
||||
{
|
||||
//Calculate current viewing window onto the content
|
||||
Point topLeftContentSpace = TranslatePoint(new Point(0, 0), Children[0]);
|
||||
Point bottomRightContentSpace = TranslatePoint(new Point(ActualWidth, ActualHeight), Children[0]);
|
||||
Rect curView = new Rect
|
||||
{
|
||||
Location = topLeftContentSpace,
|
||||
Size = new Size(bottomRightContentSpace.X - topLeftContentSpace.X, bottomRightContentSpace.Y - topLeftContentSpace.Y)
|
||||
};
|
||||
|
||||
//Mouse position as a fraction of the view size
|
||||
Point relZoomPoint = new Point
|
||||
{
|
||||
X = zoomCenter.X / this.ActualWidth,
|
||||
Y = zoomCenter.Y / this.ActualHeight
|
||||
};
|
||||
|
||||
//Calculate new viewing window
|
||||
Rect newView = ZoomView(curView, oldScale, newScale, relZoomPoint);
|
||||
|
||||
//Calculate new content offset based on the new view
|
||||
Point newOffset = new Point(-newView.X * newScale, -newView.Y * newScale);
|
||||
|
||||
//Calculate new viewing window scale
|
||||
ScaleTransform newScaleTransform = new ScaleTransform
|
||||
{
|
||||
ScaleX = newScale,
|
||||
ScaleY = newScale
|
||||
};
|
||||
|
||||
var zoomEvent = new ZoomEventArgs(parentEvent, new ScaleTransform(oldScale, oldScale), newScaleTransform, newOffset);
|
||||
Zoom?.Invoke(this, zoomEvent);
|
||||
|
||||
ApplyZoomToChildren(zoomEvent);
|
||||
DragOffset = new Point(zoomEvent.ContentOffset.X, zoomEvent.ContentOffset.Y);
|
||||
_wheelOffset = 10d * Math.Pow(Math.E, newScale / 2) - 10;
|
||||
}
|
||||
|
||||
private void ApplyZoomToChildren(ZoomEventArgs e)
|
||||
{
|
||||
foreach (UIElement cur in this.Children)
|
||||
{
|
||||
cur.RenderTransform = e.NewScale;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Viewport
|
||||
/// <summary>
|
||||
/// Centers the canvas and sets the minimum zoom factor for the specified viewport.
|
||||
/// </summary>
|
||||
/// <param name="viewport">The desired viewport.</param>
|
||||
public void SetViewport(Rect viewport)
|
||||
{
|
||||
// Get current view size
|
||||
var topLeftContentSpace = TranslatePoint(new Point(0, 0), Children[0]);
|
||||
var bottomRightContentSpace = TranslatePoint(new Point(ActualWidth, ActualHeight), Children[0]);
|
||||
var curViewSize = new Size(bottomRightContentSpace.X - topLeftContentSpace.X, bottomRightContentSpace.Y - topLeftContentSpace.Y);
|
||||
|
||||
// Calc new scale
|
||||
var oldZoom = ZoomFactor;
|
||||
var newScaleX = oldZoom * curViewSize.Width / viewport.Width;
|
||||
var newScaleY = oldZoom * curViewSize.Height / viewport.Height;
|
||||
// Calc new zoom
|
||||
var zoom = Math.Min(newScaleX, newScaleY);
|
||||
ZoomFactor = zoom;
|
||||
|
||||
this.UpdateLayout();
|
||||
|
||||
var boundingCenter = new Point(viewport.TopLeft.X + viewport.Width / 2d, viewport.TopLeft.Y + viewport.Height / 2d);
|
||||
|
||||
// Update current view size
|
||||
topLeftContentSpace = TranslatePoint(new Point(0, 0), Children[0]);
|
||||
bottomRightContentSpace = TranslatePoint(new Point(ActualWidth, ActualHeight), Children[0]);
|
||||
curViewSize = new Size(bottomRightContentSpace.X - topLeftContentSpace.X, bottomRightContentSpace.Y - topLeftContentSpace.Y);
|
||||
|
||||
// Calc new position offset
|
||||
var viewOffset = new Point(boundingCenter.X - curViewSize.Width / 2d, boundingCenter.Y - curViewSize.Height / 2d);
|
||||
this.DragOffset = new Point(-viewOffset.X * ZoomFactor, -viewOffset.Y * ZoomFactor);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class DragMoveEventArgs : EventArgs
|
||||
{
|
||||
public MouseEventArgs MouseEvent { get; }
|
||||
public double DeltaX { get; }
|
||||
public double DeltaY { get; }
|
||||
|
||||
public DragMoveEventArgs(MouseEventArgs mouseEvent, double deltaX, double deltaY)
|
||||
{
|
||||
this.MouseEvent = mouseEvent;
|
||||
this.DeltaX = deltaX;
|
||||
this.DeltaY = deltaY;
|
||||
}
|
||||
}
|
||||
|
||||
public class ZoomEventArgs : EventArgs
|
||||
{
|
||||
public MouseEventArgs MouseEvent { get; }
|
||||
public ScaleTransform OldScaleScale { get; }
|
||||
public ScaleTransform NewScale { get; }
|
||||
public Point ContentOffset { get; }
|
||||
|
||||
public ZoomEventArgs(MouseEventArgs e, ScaleTransform oldScale, ScaleTransform newScale, Point contentOffset)
|
||||
{
|
||||
this.MouseEvent = e;
|
||||
this.OldScaleScale = oldScale;
|
||||
this.NewScale = newScale;
|
||||
this.ContentOffset = contentOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
intromat/NodeNetwork/Views/Controls/FillPanel.cs
Normal file
43
intromat/NodeNetwork/Views/Controls/FillPanel.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace NodeNetwork.Views.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple panel that stretches its children to fill the panel.
|
||||
/// </summary>
|
||||
public class FillPanel : Panel
|
||||
{
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
Size maxSize = new Size(0, 0);
|
||||
|
||||
foreach (UIElement e in InternalChildren)
|
||||
{
|
||||
e.Measure(availableSize);
|
||||
maxSize = new Size(
|
||||
Math.Max(maxSize.Width, e.DesiredSize.Width),
|
||||
Math.Max(maxSize.Height, e.DesiredSize.Height)
|
||||
);
|
||||
}
|
||||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
Rect size = new Rect(new Point(), finalSize);
|
||||
foreach (UIElement e in InternalChildren)
|
||||
{
|
||||
e.Arrange(size);
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
<reactiveUi:ViewModelViewHost x:Class="NodeNetwork.Views.Controls.ViewModelViewHostNoAnimations"
|
||||
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:NodeNetwork.Views.Controls"
|
||||
xmlns:reactiveUi="http://reactiveui.net"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<reactiveUi:ViewModelViewHost.Style>
|
||||
<Style TargetType="reactiveUi:TransitioningContentControl">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="reactiveUi:TransitioningContentControl">
|
||||
<Grid
|
||||
x:Name="PART_Container"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="PresentationStates">
|
||||
|
||||
|
||||
<VisualState x:Name="Normal">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_Fade">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_SlideLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_SlideRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_SlideDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_SlideUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_MoveLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="30"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_MoveRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="30"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_MoveDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="30"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_MoveUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="30"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_DropDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="30"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_DropUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="30"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_DropRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="30"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_DropLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="30"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1" To="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceLeftIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-90" To="0">
|
||||
</DoubleAnimation>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1">
|
||||
</DoubleAnimation>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceLeftOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="-90"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceRightIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-90" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceRightOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0" To="-90"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceUpIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-90" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceUpOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="-90"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceDownIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-90" To="0"/>
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0" To="1"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Transition_BounceDownOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00" Duration="00:00:00"
|
||||
Storyboard.TargetName="PART_PreviousContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0" To="-90"/>
|
||||
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="PART_CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="PART_PreviousContentPresentationSite"
|
||||
Content="{x:Null}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ContentPresenter.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TransformGroup.Children>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1" />
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</TransformGroup.Children>
|
||||
</TransformGroup>
|
||||
</ContentPresenter.RenderTransform>
|
||||
</ContentPresenter>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="PART_CurrentContentPresentationSite"
|
||||
Content="{x:Null}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ContentPresenter.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TransformGroup.Children>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1" />
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</TransformGroup.Children>
|
||||
</TransformGroup>
|
||||
</ContentPresenter.RenderTransform>
|
||||
</ContentPresenter>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</reactiveUi:ViewModelViewHost.Style>
|
||||
</reactiveUi:ViewModelViewHost>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views.Controls
|
||||
{
|
||||
public partial class ViewModelViewHostNoAnimations : ViewModelViewHost
|
||||
{
|
||||
public ViewModelViewHostNoAnimations()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
64
intromat/NodeNetwork/Views/EndpointGroupView.cs
Normal file
64
intromat/NodeNetwork/Views/EndpointGroupView.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using NodeNetwork.Utilities;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(NameLabel), Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = nameof(InputsList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(OutputsList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(EndpointGroupsList), Type = typeof(ItemsControl))]
|
||||
public class EndpointGroupView : ReactiveUserControl<EndpointGroupViewModel>
|
||||
{
|
||||
private TextBlock NameLabel { get; set; }
|
||||
private ItemsControl InputsList { get; set; }
|
||||
private ItemsControl OutputsList { get; set; }
|
||||
private ItemsControl EndpointGroupsList { get; set; }
|
||||
|
||||
#region Properties
|
||||
public static readonly DependencyProperty TitleFontFamilyProperty = DependencyProperty.Register(nameof(TitleFontFamily), typeof(FontFamily), typeof(EndpointGroupView));
|
||||
public FontFamily TitleFontFamily
|
||||
{
|
||||
get => (FontFamily)GetValue(TitleFontFamilyProperty);
|
||||
set => SetValue(TitleFontFamilyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register(nameof(TitleFontSize), typeof(double), typeof(EndpointGroupView));
|
||||
public double TitleFontSize
|
||||
{
|
||||
get => (double)GetValue(TitleFontSizeProperty);
|
||||
set => SetValue(TitleFontSizeProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public EndpointGroupView()
|
||||
{
|
||||
DefaultStyleKey = typeof(EndpointGroupView);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.Group.Name, v => v.NameLabel.Text).DisposeWith(d);
|
||||
|
||||
this.BindList(ViewModel, vm => vm.VisibleInputs, v => v.InputsList.ItemsSource).DisposeWith(d);
|
||||
this.BindList(ViewModel, vm => vm.VisibleOutputs, v => v.OutputsList.ItemsSource).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Children, v => v.EndpointGroupsList.ItemsSource).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
NameLabel = GetTemplateChild(nameof(NameLabel)) as TextBlock;
|
||||
InputsList = GetTemplateChild(nameof(InputsList)) as ItemsControl;
|
||||
OutputsList = GetTemplateChild(nameof(OutputsList)) as ItemsControl;
|
||||
EndpointGroupsList = GetTemplateChild(nameof(EndpointGroupsList)) as ItemsControl;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
intromat/NodeNetwork/Views/ErrorMessageView.cs
Normal file
56
intromat/NodeNetwork/Views/ErrorMessageView.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
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 NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(TextBlock), Type = typeof(TextBlock))]
|
||||
public class ErrorMessageView : Control, IViewFor<ErrorMessageViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(ErrorMessageViewModel), typeof(ErrorMessageView), new PropertyMetadata(null));
|
||||
|
||||
public ErrorMessageViewModel ViewModel
|
||||
{
|
||||
get => (ErrorMessageViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ErrorMessageViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private TextBlock TextBlock { get; set; }
|
||||
|
||||
public ErrorMessageView()
|
||||
{
|
||||
DefaultStyleKey = typeof(ErrorMessageView);
|
||||
|
||||
SetupBindings();
|
||||
}
|
||||
|
||||
private void SetupBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.Message, v => v.TextBlock.Text).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
TextBlock = GetTemplateChild(nameof(TextBlock)) as TextBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
87
intromat/NodeNetwork/Views/NetworkView.xaml
Normal file
87
intromat/NodeNetwork/Views/NetworkView.xaml
Normal file
@@ -0,0 +1,87 @@
|
||||
<UserControl x:Class="NodeNetwork.Views.NetworkView"
|
||||
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:NodeNetwork.Views"
|
||||
xmlns:controls="clr-namespace:NodeNetwork.Views.Controls"
|
||||
xmlns:reactiveUi="http://reactiveui.net"
|
||||
xmlns:viewModels="clr-namespace:NodeNetwork.ViewModels"
|
||||
xmlns:wpf="clr-namespace:NodeNetwork.Utilities.WPF"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="500" d:DesignWidth="800" Focusable="True" AllowDrop="True" x:Name="self" Background="#333">
|
||||
<UserControl.InputBindings>
|
||||
<KeyBinding x:Name="deleteBinding" Key="Delete"/>
|
||||
</UserControl.InputBindings>
|
||||
<UserControl.Resources>
|
||||
<wpf:BoolToZIndexConverter x:Key="BoolToZIndexConverter"/>
|
||||
</UserControl.Resources>
|
||||
<Grid Focusable="True" KeyboardNavigation.IsTabStop="False">
|
||||
<controls:DragCanvas Zoom="DragCanvas_OnZoom" x:Name="dragCanvas" MouseLeftButtonDown="OnClickCanvas" Background="#01000000">
|
||||
<Canvas Name="contentContainer" LayoutUpdated="ContentContainer_OnLayoutUpdated" Width="{Binding ActualWidth, ElementName=dragCanvas}" Height="{Binding ActualHeight, ElementName=dragCanvas}">
|
||||
<Canvas.Clip>
|
||||
<RectangleGeometry x:Name="clippingGeometry"/>
|
||||
</Canvas.Clip>
|
||||
|
||||
<!-- Bit of a hack, but this allows backgrounds that move with the nodes and connections.
|
||||
Had to use a separate giant canvas because contentContainer is actually pretty small and any control higher won't have the image moving properly.
|
||||
-->
|
||||
<Canvas Name="backgroundCanvas" IsHitTestVisible="False" Width="1E15" Height="1E15" Canvas.Left="-1E6" Canvas.Top="-1E6" Background="{Binding NetworkBackground, ElementName=self}"/>
|
||||
|
||||
<ItemsControl x:Name="connectionsControl" Width="{Binding ActualWidth, ElementName=contentContainer}" Height="{Binding ActualHeight, ElementName=contentContainer}" IsTabStop="False">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:ViewModelViewHostNoAnimations ViewModel="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas></Canvas>
|
||||
</ItemsPanelTemplate>
|
||||
<!-- Stop connections from stacking -->
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<ItemsControl x:Name="nodesControl" Width="{Binding ActualWidth, ElementName=contentContainer}" Height="{Binding ActualHeight, ElementName=contentContainer}" IsTabStop="False">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="viewModels:NodeViewModel">
|
||||
<Canvas>
|
||||
<!-- When modifying, check the comment in NetworkView.OnNodeDragStart -->
|
||||
<Thumb DragStarted="OnNodeDragStart" DragDelta="OnNodeDrag" DragCompleted="OnNodeDragEnd" Canvas.Left="{Binding Path=Position.X}" Canvas.Top="{Binding Path=Position.Y}">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate>
|
||||
<controls:ViewModelViewHostNoAnimations ViewModel="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Canvas>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ContentPresenter}">
|
||||
<Style.Setters>
|
||||
<Setter Property="Panel.ZIndex" Value="{Binding Path=IsSelected, Converter={StaticResource BoolToZIndexConverter}}"/>
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
</ItemsControl>
|
||||
|
||||
<Line x:Name="cutLine" Stroke="LightGray" StrokeDashArray="2, 4" StrokeThickness="1" />
|
||||
|
||||
<Rectangle x:Name="selectionRectangle" Stroke="White" Fill="Transparent" StrokeDashArray="2, 4" StrokeThickness="1"/>
|
||||
|
||||
<controls:ViewModelViewHostNoAnimations x:Name="pendingConnectionView" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" IsTabStop="False"/>
|
||||
|
||||
<controls:ViewModelViewHostNoAnimations x:Name="pendingNodeView" Opacity="0.5" IsTabStop="False"/>
|
||||
</Canvas>
|
||||
</controls:DragCanvas>
|
||||
|
||||
<Popup x:Name="messagePopup" Placement="Top" StaysOpen="True" HorizontalAlignment="Right">
|
||||
<reactiveUi:ViewModelViewHost Name="messagePopupHost" IsTabStop="False"/>
|
||||
</Popup>
|
||||
|
||||
<Border Name="messageHostBorder" Background="#EEE" CornerRadius="5" HorizontalAlignment="Center" VerticalAlignment="Top" Padding="10, 10, 10, 10" Margin="20">
|
||||
<reactiveUi:ViewModelViewHost Name="messageHost" IsTabStop="False"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
581
intromat/NodeNetwork/Views/NetworkView.xaml.cs
Normal file
581
intromat/NodeNetwork/Views/NetworkView.xaml.cs
Normal file
@@ -0,0 +1,581 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using DynamicData;
|
||||
using NodeNetwork.Utilities;
|
||||
using NodeNetwork.ViewModels;
|
||||
using NodeNetwork.Views.Controls;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
public partial class NetworkView : IViewFor<NetworkViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(NetworkViewModel), typeof(NetworkView), new PropertyMetadata(null));
|
||||
|
||||
public NetworkViewModel ViewModel
|
||||
{
|
||||
get => (NetworkViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (NetworkViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NetworkViewportRegion
|
||||
/// <summary>
|
||||
/// The rectangle to use as a clipping mask for contentContainer
|
||||
/// </summary>
|
||||
public Rect NetworkViewportRegion
|
||||
{
|
||||
get
|
||||
{
|
||||
double left = Canvas.GetLeft(contentContainer);
|
||||
if (Double.IsNaN(left))
|
||||
{
|
||||
left = 0;
|
||||
}
|
||||
|
||||
double top = Canvas.GetTop(contentContainer);
|
||||
if (Double.IsNaN(top))
|
||||
{
|
||||
top = 0;
|
||||
}
|
||||
|
||||
if (contentContainer.RenderTransform is ScaleTransform)
|
||||
{
|
||||
GeneralTransform transform = this.TransformToDescendant(contentContainer);
|
||||
return transform.TransformBounds(new Rect(0, 0, this.ActualWidth, this.ActualHeight));
|
||||
}
|
||||
return new Rect(-left, -top, this.ActualWidth, this.ActualHeight);
|
||||
}
|
||||
}
|
||||
private BindingExpressionBase _viewportBinding;
|
||||
#endregion
|
||||
|
||||
#region Node move events
|
||||
public class NodeMovementEventArgs : EventArgs
|
||||
{
|
||||
public IEnumerable<NodeViewModel> Nodes { get; }
|
||||
public NodeMovementEventArgs(IEnumerable<NodeViewModel> nodes) => Nodes = nodes.ToList();
|
||||
}
|
||||
|
||||
//Start
|
||||
public class NodeMoveStartEventArgs : NodeMovementEventArgs
|
||||
{
|
||||
public DragStartedEventArgs DragEvent { get; }
|
||||
|
||||
public NodeMoveStartEventArgs(IEnumerable<NodeViewModel> nodes, DragStartedEventArgs dragEvent) :
|
||||
base(nodes)
|
||||
{
|
||||
DragEvent = dragEvent;
|
||||
}
|
||||
}
|
||||
public delegate void NodeMoveStartDelegate(object sender, NodeMoveStartEventArgs e);
|
||||
/// <summary>Occurs when a (set of) node(s) is selected and starts moving.</summary>
|
||||
public event NodeMoveStartDelegate NodeMoveStart;
|
||||
|
||||
//Move
|
||||
public class NodeMoveEventArgs : NodeMovementEventArgs
|
||||
{
|
||||
public DragDeltaEventArgs DragEvent { get; }
|
||||
|
||||
public NodeMoveEventArgs(IEnumerable<NodeViewModel> nodes, DragDeltaEventArgs dragEvent) : base(nodes)
|
||||
{
|
||||
DragEvent = dragEvent;
|
||||
}
|
||||
}
|
||||
public delegate void NodeMoveDelegate(object sender, NodeMoveEventArgs e);
|
||||
/// <summary>Occurs one or more times as the mouse changes position when a (set of) node(s) is selected and has mouse capture.</summary>
|
||||
public event NodeMoveDelegate NodeMove;
|
||||
|
||||
//End
|
||||
public class NodeMoveEndEventArgs : NodeMovementEventArgs
|
||||
{
|
||||
public DragCompletedEventArgs DragEvent { get; }
|
||||
|
||||
public NodeMoveEndEventArgs(IEnumerable<NodeViewModel> nodes, DragCompletedEventArgs dragEvent) : base(nodes)
|
||||
{
|
||||
DragEvent = dragEvent;
|
||||
}
|
||||
}
|
||||
public delegate void NodeMoveEndDelegate(object sender, NodeMoveEndEventArgs e);
|
||||
/// <summary>Occurs when a (set of) node(s) loses mouse capture.</summary>
|
||||
public event NodeMoveEndDelegate NodeMoveEnd;
|
||||
#endregion
|
||||
|
||||
#region NetworkBackground
|
||||
public static readonly DependencyProperty NetworkBackgroundProperty = DependencyProperty.Register(nameof(NetworkBackground),
|
||||
typeof(Brush), typeof(NetworkView), new PropertyMetadata(null));
|
||||
|
||||
public Brush NetworkBackground
|
||||
{
|
||||
get => (Brush)GetValue(NetworkBackgroundProperty);
|
||||
set => SetValue(NetworkBackgroundProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The element that is used as an origin for the position of the elements of the network.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Can be used for calculating the mouse position relative to the network.
|
||||
/// <code>
|
||||
/// Mouse.GetPosition(network.CanvasOriginElement)
|
||||
/// </code>
|
||||
/// </example>
|
||||
public IInputElement CanvasOriginElement => contentContainer;
|
||||
|
||||
#region StartCutGesture
|
||||
public static readonly DependencyProperty StartCutGestureProperty = DependencyProperty.Register(nameof(StartCutGesture),
|
||||
typeof(MouseGesture), typeof(NetworkView), new PropertyMetadata(new MouseGesture(MouseAction.RightClick)));
|
||||
|
||||
/// <summary>
|
||||
/// This mouse gesture starts a cut, making the cutline visible. Right click by default.
|
||||
/// </summary>
|
||||
public MouseGesture StartCutGesture
|
||||
{
|
||||
get => (MouseGesture)GetValue(StartCutGestureProperty);
|
||||
set => SetValue(StartCutGestureProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region StartSelectionRectangleGesture
|
||||
public static readonly DependencyProperty StartSelectionRectangleGestureProperty = DependencyProperty.Register(nameof(StartSelectionRectangleGesture),
|
||||
typeof(MouseGesture), typeof(NetworkView), new PropertyMetadata(new MouseGesture(MouseAction.LeftClick, ModifierKeys.Shift)));
|
||||
|
||||
/// <summary>
|
||||
/// This mouse gesture starts a selection, making the selection rectangle visible. Left click + Shift by default.
|
||||
/// </summary>
|
||||
public MouseGesture StartSelectionRectangleGesture
|
||||
{
|
||||
get => (MouseGesture)GetValue(StartSelectionRectangleGestureProperty);
|
||||
set => SetValue(StartSelectionRectangleGestureProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public NetworkView()
|
||||
{
|
||||
InitializeComponent();
|
||||
if (DesignerProperties.GetIsInDesignMode(this)) { return; }
|
||||
|
||||
SetupNodes();
|
||||
SetupConnections();
|
||||
SetupCutLine();
|
||||
SetupViewportBinding();
|
||||
SetupKeyboardShortcuts();
|
||||
SetupErrorMessages();
|
||||
SetupDragAndDrop();
|
||||
SetupSelectionRectangle();
|
||||
}
|
||||
|
||||
#region Setup
|
||||
private void SetupNodes()
|
||||
{
|
||||
this.WhenActivated(d => d(
|
||||
this.BindList(ViewModel, vm => vm.Nodes, v => v.nodesControl.ItemsSource)
|
||||
));
|
||||
}
|
||||
|
||||
private void SetupConnections()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.BindList(ViewModel, vm => vm.Connections, v => v.connectionsControl.ItemsSource).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.PendingConnection, v => v.pendingConnectionView.ViewModel).DisposeWith(d);
|
||||
|
||||
this.Events().MouseMove
|
||||
.Select(e => e.GetPosition(contentContainer))
|
||||
.BindTo(this, v => v.ViewModel.PendingConnection.LooseEndPoint)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.Events().MouseLeftButtonUp
|
||||
.Where(_ => ViewModel.PendingConnection != null)
|
||||
.Subscribe(_ => ViewModel.OnPendingConnectionDropped())
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupKeyboardShortcuts()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.Events().MouseLeftButtonDown.Subscribe(_ => Focus()).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.DeleteSelectedNodes, v => v.deleteBinding.Command).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupCutLine()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.CutLine.StartPoint.X, v => v.cutLine.X1).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.CutLine.StartPoint.Y, v => v.cutLine.Y1).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.CutLine.EndPoint.X, v => v.cutLine.X2).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.CutLine.EndPoint.Y, v => v.cutLine.Y2).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.CutLine.IsVisible, v => v.cutLine.Visibility,
|
||||
isVisible => isVisible ? Visibility.Visible : Visibility.Collapsed)
|
||||
.DisposeWith(d);
|
||||
|
||||
bool cutGestured = false;
|
||||
dragCanvas.Events().MouseDown.Subscribe(e =>
|
||||
{
|
||||
if (StartCutGesture.Matches(this, e))
|
||||
{
|
||||
Point pos = e.GetPosition(contentContainer);
|
||||
ViewModel.CutLine.StartPoint = pos;
|
||||
ViewModel.CutLine.EndPoint = pos;
|
||||
cutGestured = true;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
|
||||
dragCanvas.Events().MouseMove.Subscribe(e =>
|
||||
{
|
||||
if (!ViewModel.CutLine.IsVisible && cutGestured)
|
||||
{
|
||||
ViewModel.StartCut();
|
||||
}
|
||||
|
||||
if (ViewModel.CutLine.IsVisible)
|
||||
{
|
||||
ViewModel.CutLine.EndPoint = e.GetPosition(contentContainer);
|
||||
|
||||
ViewModel.CutLine.IntersectingConnections.Edit(l =>
|
||||
{
|
||||
l.Clear();
|
||||
l.AddRange(FindIntersectingConnections().Where(val => val.intersects).Select(val => val.con));
|
||||
});
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
}).DisposeWith(d);
|
||||
|
||||
dragCanvas.Events().MouseUp.Subscribe(e =>
|
||||
{
|
||||
cutGestured = false;
|
||||
if (ViewModel.CutLine.IsVisible)
|
||||
{
|
||||
//Do cuts
|
||||
ViewModel.FinishCut();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupViewportBinding()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.ZoomFactor, v => v.dragCanvas.ZoomFactor);
|
||||
this.Bind(ViewModel, vm => vm.MaxZoomLevel, v => v.dragCanvas.MaxZoomFactor);
|
||||
this.Bind(ViewModel, vm => vm.MinZoomLevel, v => v.dragCanvas.MinZoomFactor);
|
||||
this.Bind(ViewModel, vm => vm.DragOffset, v => v.dragCanvas.DragOffset);
|
||||
});
|
||||
|
||||
Binding binding = new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath(nameof(NetworkViewportRegion)),
|
||||
Mode = BindingMode.OneWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||
};
|
||||
_viewportBinding = BindingOperations.SetBinding(clippingGeometry, RectangleGeometry.RectProperty, binding);
|
||||
}
|
||||
|
||||
private void SetupErrorMessages()
|
||||
{
|
||||
messageHostBorder.Visibility = Visibility.Collapsed; //Start collapsed
|
||||
messagePopup.VerticalOffset = -15;
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.LatestValidation.IsValid, v => v.messageHostBorder.Visibility,
|
||||
isValid => isValid ? Visibility.Collapsed : Visibility.Visible)
|
||||
.DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.LatestValidation.MessageViewModel, v => v.messageHost.ViewModel)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.PendingConnection.Validation)
|
||||
.Select(_ => ViewModel.PendingConnection?.Validation?.MessageViewModel != null)
|
||||
.BindTo(this, v => v.messagePopup.IsOpen)
|
||||
.DisposeWith(d);
|
||||
this.WhenAnyValue(v => v.ViewModel.PendingConnection.Validation)
|
||||
.Select(_ => ViewModel.PendingConnection?.Validation?.MessageViewModel)
|
||||
.BindTo(this, v => v.messagePopupHost.ViewModel)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(vm => vm.ViewModel.PendingConnection.BoundingBox)
|
||||
.Select(b => new Rect(contentContainer.TranslatePoint(b.TopLeft, this), contentContainer.TranslatePoint(b.BottomRight, this)))
|
||||
.BindTo(this, v => v.messagePopup.PlacementRectangle)
|
||||
.DisposeWith(d);
|
||||
this.WhenAnyValue(vm => vm.ViewModel.PendingConnection.BoundingBox)
|
||||
.Select(b => (b.Width / 2d) - (messagePopup.Child.RenderSize.Width / 2d))
|
||||
.BindTo(this, v => v.messagePopup.HorizontalOffset)
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupDragAndDrop()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.PendingNode, v => v.pendingNodeView.ViewModel).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.PendingNode, v => v.pendingNodeView.Visibility,
|
||||
node => node == null ? Visibility.Collapsed : Visibility.Visible)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.PendingNode.Position).Subscribe(pos =>
|
||||
{
|
||||
Canvas.SetLeft(pendingNodeView, pos.X);
|
||||
Canvas.SetTop(pendingNodeView, pos.Y);
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.Events().DragOver.Subscribe(e =>
|
||||
{
|
||||
object data = e.Data.GetData("nodeVM");
|
||||
NodeViewModel newNodeVm = data as NodeViewModel;
|
||||
|
||||
ViewModel.PendingNode = newNodeVm;
|
||||
if (ViewModel.PendingNode != null)
|
||||
{
|
||||
ViewModel.PendingNode.Position = e.GetPosition(contentContainer);
|
||||
}
|
||||
|
||||
e.Effects = newNodeVm != null ? DragDropEffects.Copy : DragDropEffects.None;
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.Events().Drop.Subscribe(e =>
|
||||
{
|
||||
object data = e.Data.GetData("nodeVM");
|
||||
NodeViewModel newNodeVm = data as NodeViewModel;
|
||||
if (newNodeVm != null)
|
||||
{
|
||||
this.ViewModel.PendingNode =
|
||||
new NodeViewModel(); //Fixes issue with newNodeVm sticking around in pendingNodeView, messing up position updates
|
||||
this.ViewModel.PendingNode = null;
|
||||
newNodeVm.Position = e.GetPosition(contentContainer);
|
||||
ViewModel.Nodes.Add(newNodeVm);
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.Events().DragLeave.Subscribe(_ => ViewModel.PendingNode = null).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupSelectionRectangle()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.WhenAnyValue(vm => vm.ViewModel.SelectionRectangle.Rectangle.Left)
|
||||
.Subscribe(left => Canvas.SetLeft(selectionRectangle, left))
|
||||
.DisposeWith(d);
|
||||
this.WhenAnyValue(vm => vm.ViewModel.SelectionRectangle.Rectangle.Top)
|
||||
.Subscribe(top => Canvas.SetTop(selectionRectangle, top))
|
||||
.DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.SelectionRectangle.Rectangle.Width, v => v.selectionRectangle.Width).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.SelectionRectangle.Rectangle.Height, v => v.selectionRectangle.Height).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.SelectionRectangle.IsVisible, v => v.selectionRectangle.Visibility).DisposeWith(d);
|
||||
|
||||
this.Events().PreviewMouseDown.Subscribe(e =>
|
||||
{
|
||||
if (ViewModel != null && StartSelectionRectangleGesture.Matches(this, e))
|
||||
{
|
||||
CaptureMouse();
|
||||
dragCanvas.IsDraggingEnabled = false;
|
||||
ViewModel.StartRectangleSelection();
|
||||
ViewModel.SelectionRectangle.StartPoint = e.GetPosition(contentContainer);
|
||||
ViewModel.SelectionRectangle.EndPoint = ViewModel.SelectionRectangle.StartPoint;
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.Events().MouseMove.Subscribe(e =>
|
||||
{
|
||||
if (ViewModel != null && ViewModel.SelectionRectangle.IsVisible)
|
||||
{
|
||||
ViewModel.SelectionRectangle.EndPoint = e.GetPosition(contentContainer);
|
||||
UpdateSelectionRectangleIntersections();
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.Events().MouseUp.Subscribe(e =>
|
||||
{
|
||||
if (ViewModel != null && ViewModel.SelectionRectangle.IsVisible)
|
||||
{
|
||||
ViewModel.FinishRectangleSelection();
|
||||
dragCanvas.IsDraggingEnabled = true;
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
// Real, accurate but expensive hittesting
|
||||
/*private void UpdateSelectionRectangleIntersections()
|
||||
{
|
||||
RectangleGeometry geometry = new RectangleGeometry(ViewModel.SelectionRectangle.Rectangle);
|
||||
|
||||
ViewModel.SelectionRectangle.IntersectingNodes.Clear();
|
||||
VisualTreeHelper.HitTest(nodesControl, element =>
|
||||
{
|
||||
if (element is NodeView)
|
||||
{
|
||||
//return HitTestFilterBehavior.ContinueSkipChildren;
|
||||
}
|
||||
|
||||
return HitTestFilterBehavior.Continue;
|
||||
}, result =>
|
||||
{
|
||||
if ((result.VisualHit as FrameworkElement)?.DataContext is NodeViewModel nodeVm &&
|
||||
!ViewModel.SelectionRectangle.IntersectingNodes.Contains(nodeVm))
|
||||
{
|
||||
Debug.WriteLine(result.VisualHit);
|
||||
ViewModel.SelectionRectangle.IntersectingNodes.Add(nodeVm);
|
||||
}
|
||||
|
||||
return HitTestResultBehavior.Continue;
|
||||
}, new GeometryHitTestParameters(geometry));
|
||||
}*/
|
||||
|
||||
// Approximate but cheap boundingbox-based hittesting
|
||||
private void UpdateSelectionRectangleIntersections()
|
||||
{
|
||||
var selectionRect = ViewModel.SelectionRectangle.Rectangle;
|
||||
|
||||
var nodesHit = WPFUtils.FindDescendantsOfType<NodeViewBase>(nodesControl, true)
|
||||
.Where(nodeView =>
|
||||
{
|
||||
//return selectionRect.Contains(new Rect(nodeView.ViewModel.Position, nodeView.RenderSize));
|
||||
var viewModel = (NodeViewModel)((dynamic)nodeView).ViewModel;
|
||||
return selectionRect.IntersectsWith(new Rect(viewModel.Position, nodeView.RenderSize));
|
||||
})
|
||||
.Select(view => (NodeViewModel)((dynamic)view).ViewModel);
|
||||
|
||||
ViewModel.SelectionRectangle.IntersectingNodes.Clear();
|
||||
ViewModel.SelectionRectangle.IntersectingNodes.AddRange(nodesHit);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Viewport bound updates
|
||||
private void DragCanvas_OnZoom(object source, ZoomEventArgs args)
|
||||
{
|
||||
_viewportBinding?.UpdateTarget();
|
||||
}
|
||||
|
||||
private void ContentContainer_OnLayoutUpdated(object sender, EventArgs e)
|
||||
{
|
||||
_viewportBinding?.UpdateTarget();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Node move events
|
||||
private void OnNodeDragStart(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
// Hacky fix for issue #78. A nested thumb being dragged would also drag the node around, which is incorrect.
|
||||
// For some reason, trying to stop the MouseMove event from bubbling up does not work, so instead we check
|
||||
// here what caused this drag event. Only the Thumb around the node may cause drag events.
|
||||
|
||||
bool isCorrectSource = WPFUtils.GetVisualAncestorNLevelsUp((DependencyObject)e.OriginalSource, 6) == nodesControl;
|
||||
if (NodeMoveStart != null && isCorrectSource)
|
||||
{
|
||||
var args = new NodeMoveStartEventArgs(ViewModel.SelectedNodes.Items, e);
|
||||
NodeMoveStart(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNodeDrag(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
// See OnNodeDragStart
|
||||
bool isCorrectSource = WPFUtils.GetVisualAncestorNLevelsUp((DependencyObject)e.OriginalSource, 6) == nodesControl;
|
||||
if (isCorrectSource)
|
||||
{
|
||||
foreach (NodeViewModel node in ViewModel.SelectedNodes.Items)
|
||||
{
|
||||
node.Position = new Point(node.Position.X + e.HorizontalChange, node.Position.Y + e.VerticalChange);
|
||||
}
|
||||
|
||||
if (NodeMove != null)
|
||||
{
|
||||
var args = new NodeMoveEventArgs(ViewModel.SelectedNodes.Items, e);
|
||||
NodeMove(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNodeDragEnd(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
// See OnNodeDragStart
|
||||
bool isCorrectSource = WPFUtils.GetVisualAncestorNLevelsUp((DependencyObject)e.OriginalSource, 6) == nodesControl;
|
||||
if (NodeMoveEnd != null && isCorrectSource)
|
||||
{
|
||||
var args = new NodeMoveEndEventArgs(ViewModel.SelectedNodes.Items, e);
|
||||
NodeMoveEnd(sender, args);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnClickCanvas(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ViewModel.ClearSelection();
|
||||
}
|
||||
|
||||
private IEnumerable<(ConnectionViewModel con, bool intersects)> FindIntersectingConnections()
|
||||
{
|
||||
foreach (ConnectionViewModel con in ViewModel.Connections.Items)
|
||||
{
|
||||
PathGeometry conGeom = ConnectionView.BuildSmoothBezier(con.Input.Port.CenterPoint, con.Input.PortPosition, con.Output.Port.CenterPoint, con.Output.PortPosition);
|
||||
LineGeometry cutLineGeom = new LineGeometry(ViewModel.CutLine.StartPoint, ViewModel.CutLine.EndPoint);
|
||||
bool hasIntersections = WPFUtils.GetIntersectionPoints(conGeom, cutLineGeom).Any();
|
||||
yield return (con, hasIntersections);
|
||||
}
|
||||
}
|
||||
|
||||
public void CenterAndZoomView()
|
||||
{
|
||||
if (ViewModel.Nodes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bounding = ViewModel.Nodes.Items.Select(node =>
|
||||
{
|
||||
var currentTopLeft = node.Position;
|
||||
var currentBottomRight = Point.Add(node.Position, new Vector(node.Size.Width, node.Size.Height));
|
||||
var nodeBounding = new Rect(currentTopLeft, currentBottomRight);
|
||||
return nodeBounding;
|
||||
}).Aggregate((r1, r2) =>
|
||||
{
|
||||
r1.Union(r2);
|
||||
return r1;
|
||||
});
|
||||
|
||||
this.dragCanvas?.SetViewport(bounding);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
intromat/NodeNetwork/Views/NodeEndpointEditorView.cs
Normal file
37
intromat/NodeNetwork/Views/NodeEndpointEditorView.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
public class NodeEndpointEditorView : Control, IViewFor<NodeEndpointEditorViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(NodeEndpointEditorViewModel), typeof(NodeEndpointEditorView), new PropertyMetadata(null));
|
||||
|
||||
public NodeEndpointEditorViewModel ViewModel
|
||||
{
|
||||
get => (NodeEndpointEditorViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (NodeEndpointEditorViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public NodeEndpointEditorView()
|
||||
{
|
||||
DefaultStyleKey = typeof(NodeEndpointEditorView);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
intromat/NodeNetwork/Views/NodeInputView.cs
Normal file
89
intromat/NodeNetwork/Views/NodeInputView.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(EndpointHost), Type = typeof(ViewModelViewHost))]
|
||||
[TemplatePart(Name = nameof(EditorHost), Type = typeof(ViewModelViewHost))]
|
||||
[TemplatePart(Name = nameof(NameLabel), Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = nameof(Icon), Type = typeof(Image))]
|
||||
public class NodeInputView : Control, IViewFor<NodeInputViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(NodeInputViewModel), typeof(NodeInputView), new PropertyMetadata(null));
|
||||
|
||||
public NodeInputViewModel ViewModel
|
||||
{
|
||||
get => (NodeInputViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (NodeInputViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private ViewModelViewHost EndpointHost { get; set; }
|
||||
private ViewModelViewHost EditorHost { get; set; }
|
||||
private TextBlock NameLabel { get; set; }
|
||||
private Image Icon { get; set; }
|
||||
|
||||
private bool _isHeaderEmpty;
|
||||
|
||||
public NodeInputView()
|
||||
{
|
||||
DefaultStyleKey = typeof(NodeInputView);
|
||||
|
||||
SetupBindings();
|
||||
}
|
||||
|
||||
private void SetupBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.Name, v => v.NameLabel.Text).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Port, v => v.EndpointHost.ViewModel).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Port.IsVisible, v => v.EndpointHost.Visibility).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Editor, v => v.EditorHost.ViewModel).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.IsEditorVisible, v => v.EditorHost.Visibility).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Icon, v => v.Icon.Source, img => img?.ToNative()).DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.Name, v => v.ViewModel.Icon,
|
||||
(name, icon) => String.IsNullOrEmpty(name) && icon == null)
|
||||
.Subscribe(v =>
|
||||
{
|
||||
_isHeaderEmpty = v;
|
||||
if(EditorHost != null)
|
||||
{
|
||||
Grid.SetRow(EditorHost, _isHeaderEmpty ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
EndpointHost = GetTemplateChild(nameof(EndpointHost)) as ViewModelViewHost;
|
||||
EditorHost = GetTemplateChild(nameof(EditorHost)) as ViewModelViewHost;
|
||||
NameLabel = GetTemplateChild(nameof(NameLabel)) as TextBlock;
|
||||
Icon = GetTemplateChild(nameof(Icon)) as Image;
|
||||
|
||||
if (EditorHost != null)
|
||||
Grid.SetRow(EditorHost, _isHeaderEmpty ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
88
intromat/NodeNetwork/Views/NodeOutputView.cs
Normal file
88
intromat/NodeNetwork/Views/NodeOutputView.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(EndpointHost), Type = typeof(ViewModelViewHost))]
|
||||
[TemplatePart(Name = nameof(EditorHost), Type = typeof(ViewModelViewHost))]
|
||||
[TemplatePart(Name = nameof(NameLabel), Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = nameof(Icon), Type = typeof(Image))]
|
||||
public class NodeOutputView : Control, IViewFor<NodeOutputViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(NodeOutputViewModel), typeof(NodeOutputView), new PropertyMetadata(null));
|
||||
|
||||
public NodeOutputViewModel ViewModel
|
||||
{
|
||||
get => (NodeOutputViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (NodeOutputViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private ViewModelViewHost EndpointHost { get; set; }
|
||||
private ViewModelViewHost EditorHost { get; set; }
|
||||
private TextBlock NameLabel { get; set; }
|
||||
private Image Icon { get; set; }
|
||||
|
||||
private bool _isHeaderEmpty;
|
||||
|
||||
public NodeOutputView()
|
||||
{
|
||||
DefaultStyleKey = typeof(NodeOutputView);
|
||||
|
||||
SetupBindings();
|
||||
}
|
||||
|
||||
private void SetupBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.Name, v => v.NameLabel.Text).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Port, v => v.EndpointHost.ViewModel).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Port.IsVisible, v => v.EndpointHost.Visibility).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Editor, v => v.EditorHost.ViewModel).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.Icon, v => v.Icon.Source, img => img?.ToNative()).DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.Name, v => v.ViewModel.Icon,
|
||||
(name, icon) => String.IsNullOrEmpty(name) && icon == null)
|
||||
.Subscribe(v =>
|
||||
{
|
||||
_isHeaderEmpty = v;
|
||||
if (EditorHost != null)
|
||||
{
|
||||
Grid.SetRow(EditorHost, _isHeaderEmpty ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
EndpointHost = GetTemplateChild(nameof(EndpointHost)) as ViewModelViewHost;
|
||||
EditorHost = GetTemplateChild(nameof(EditorHost)) as ViewModelViewHost;
|
||||
NameLabel = GetTemplateChild(nameof(NameLabel)) as TextBlock;
|
||||
Icon = GetTemplateChild(nameof(Icon)) as Image;
|
||||
|
||||
if (EditorHost != null)
|
||||
Grid.SetRow(EditorHost, _isHeaderEmpty ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
235
intromat/NodeNetwork/Views/NodeView.cs
Normal file
235
intromat/NodeNetwork/Views/NodeView.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using NodeNetwork.Utilities;
|
||||
using NodeNetwork.ViewModels;
|
||||
using NodeNetwork.Views.Controls;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplatePart(Name = nameof(CollapseButton), Type = typeof(ArrowToggleButton))]
|
||||
[TemplatePart(Name = nameof(NameLabel), Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = nameof(HeaderIcon), Type = typeof(Image))]
|
||||
[TemplatePart(Name = nameof(InputsList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(OutputsList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(EndpointGroupsList), Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = nameof(ResizeVerticalThumb), Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = nameof(ResizeHorizontalThumb), Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = nameof(ResizeDiagonalThumb), Type = typeof(Thumb))]
|
||||
[TemplateVisualState(Name = SelectedState, GroupName = SelectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = UnselectedState, GroupName = SelectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = CollapsedState, GroupName = CollapsedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = ExpandedState, GroupName = CollapsedVisualStatesGroup)]
|
||||
public class NodeView : NodeViewBase, IViewFor<NodeViewModel>
|
||||
{
|
||||
#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(NodeViewModel), typeof(NodeView), new PropertyMetadata(null));
|
||||
|
||||
public NodeViewModel ViewModel
|
||||
{
|
||||
get => (NodeViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (NodeViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(NodeView));
|
||||
public CornerRadius CornerRadius
|
||||
{
|
||||
get => (CornerRadius)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ArrowSizeProperty = DependencyProperty.Register(nameof(ArrowSize), typeof(double), typeof(NodeView));
|
||||
public double ArrowSize
|
||||
{
|
||||
get => (double)GetValue(ArrowSizeProperty);
|
||||
set => SetValue(ArrowSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleFontFamilyProperty = DependencyProperty.Register(nameof(TitleFontFamily), typeof(FontFamily), typeof(NodeView));
|
||||
public FontFamily TitleFontFamily
|
||||
{
|
||||
get => (FontFamily)GetValue(TitleFontFamilyProperty);
|
||||
set => SetValue(TitleFontFamilyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register(nameof(TitleFontSize), typeof(double), typeof(NodeView));
|
||||
public double TitleFontSize
|
||||
{
|
||||
get => (double)GetValue(TitleFontSizeProperty);
|
||||
set => SetValue(TitleFontSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndpointsStackingOrientationProperty = DependencyProperty.Register(nameof(EndpointsStackingOrientation), typeof(Orientation), typeof(NodeView));
|
||||
public Orientation EndpointsStackingOrientation
|
||||
{
|
||||
get => (Orientation)GetValue(EndpointsStackingOrientationProperty);
|
||||
set => SetValue(EndpointsStackingOrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LeadingControlPresenterStyleProperty = DependencyProperty.Register(nameof(LeadingControlPresenterStyle), typeof(Style), typeof(NodeView));
|
||||
public Style LeadingControlPresenterStyle
|
||||
{
|
||||
get => (Style)GetValue(LeadingControlPresenterStyleProperty);
|
||||
set => SetValue(LeadingControlPresenterStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TrailingControlPresenterStyleProperty = DependencyProperty.Register(nameof(TrailingControlPresenterStyle), typeof(Style), typeof(NodeView));
|
||||
public Style TrailingControlPresenterStyle
|
||||
{
|
||||
get => (Style)GetValue(TrailingControlPresenterStyleProperty);
|
||||
set => SetValue(TrailingControlPresenterStyleProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private ArrowToggleButton CollapseButton { get; set; }
|
||||
private TextBlock NameLabel { get; set; }
|
||||
private Image HeaderIcon { get; set; }
|
||||
private ItemsControl InputsList { get; set; }
|
||||
private ItemsControl OutputsList { get; set; }
|
||||
private ItemsControl EndpointGroupsList { get; set; }
|
||||
private Thumb ResizeVerticalThumb { get; set; }
|
||||
private Thumb ResizeHorizontalThumb { get; set; }
|
||||
private Thumb ResizeDiagonalThumb { get; set; }
|
||||
|
||||
public NodeView()
|
||||
{
|
||||
DefaultStyleKey = typeof(NodeView);
|
||||
|
||||
SetupBindings();
|
||||
SetupEvents();
|
||||
SetupVisualStateBindings();
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
CollapseButton = GetTemplateChild(nameof(CollapseButton)) as ArrowToggleButton;
|
||||
NameLabel = GetTemplateChild(nameof(NameLabel)) as TextBlock;
|
||||
HeaderIcon = GetTemplateChild(nameof(HeaderIcon)) as Image;
|
||||
InputsList = GetTemplateChild(nameof(InputsList)) as ItemsControl;
|
||||
OutputsList = GetTemplateChild(nameof(OutputsList)) as ItemsControl;
|
||||
EndpointGroupsList = GetTemplateChild(nameof(EndpointGroupsList)) as ItemsControl;
|
||||
ResizeVerticalThumb = GetTemplateChild(nameof(ResizeVerticalThumb)) as Thumb;
|
||||
ResizeHorizontalThumb = GetTemplateChild(nameof(ResizeHorizontalThumb)) as Thumb;
|
||||
ResizeDiagonalThumb = GetTemplateChild(nameof(ResizeDiagonalThumb)) as Thumb;
|
||||
|
||||
ResizeVerticalThumb.DragDelta += (sender, e) => ApplyResize(e, false, true);
|
||||
ResizeHorizontalThumb.DragDelta += (sender, e) => ApplyResize(e, true, false);
|
||||
ResizeDiagonalThumb.DragDelta += (sender, e) => ApplyResize(e, true, true);
|
||||
|
||||
VisualStateManager.GoToState(this, ExpandedState, false);
|
||||
VisualStateManager.GoToState(this, UnselectedState, false);
|
||||
}
|
||||
|
||||
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 =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.IsCollapsed, v => v.CollapseButton.IsChecked).DisposeWith(d);
|
||||
|
||||
this.OneWayBind(ViewModel, vm => vm.Name, v => v.NameLabel.Text).DisposeWith(d);
|
||||
|
||||
this.BindList(ViewModel, vm => vm.VisibleInputs, v => v.InputsList.ItemsSource).DisposeWith(d);
|
||||
this.BindList(ViewModel, vm => vm.VisibleOutputs, v => v.OutputsList.ItemsSource).DisposeWith(d);
|
||||
this.OneWayBind(ViewModel, vm => vm.VisibleEndpointGroups, v => v.EndpointGroupsList.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.OneWayBind(ViewModel, vm => vm.HeaderIcon, v => v.HeaderIcon.Source, img => img?.ToNative()).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupEvents()
|
||||
{
|
||||
this.MouseLeftButtonDown += (sender, args) =>
|
||||
{
|
||||
this.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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
13
intromat/NodeNetwork/Views/NodeViewBase.cs
Normal file
13
intromat/NodeNetwork/Views/NodeViewBase.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
public class NodeViewBase : Control
|
||||
{
|
||||
}
|
||||
}
|
||||
125
intromat/NodeNetwork/Views/PendingConnectionView.cs
Normal file
125
intromat/NodeNetwork/Views/PendingConnectionView.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplateVisualState(Name = ErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
public class PendingConnectionView : Control, IViewFor<PendingConnectionViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(PendingConnectionViewModel), typeof(PendingConnectionView), new PropertyMetadata(null));
|
||||
|
||||
public PendingConnectionViewModel ViewModel
|
||||
{
|
||||
get => (PendingConnectionViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (PendingConnectionViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region States
|
||||
#region ErrorStates
|
||||
public const string ErrorVisualStatesGroup = "ErrorStates";
|
||||
public const string ErrorState = "Error";
|
||||
public const string NonErrorState = "NoError";
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region RegularBrush
|
||||
public Brush RegularBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(RegularBrushProperty);
|
||||
set => this.SetValue(RegularBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty RegularBrushProperty = DependencyProperty.Register(nameof(RegularBrush), typeof(Brush), typeof(PendingConnectionView));
|
||||
#endregion
|
||||
|
||||
#region ErrorBrush
|
||||
public Brush ErrorBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ErrorBrushProperty);
|
||||
set => this.SetValue(ErrorBrushProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ErrorBrushProperty = DependencyProperty.Register(nameof(ErrorBrush), typeof(Brush), typeof(PendingConnectionView));
|
||||
#endregion
|
||||
|
||||
#region Geometry
|
||||
public Geometry Geometry
|
||||
{
|
||||
get => (Geometry)this.GetValue(GeometryProperty);
|
||||
set => this.SetValue(GeometryProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty GeometryProperty = DependencyProperty.Register(nameof(Geometry), typeof(Geometry), typeof(PendingConnectionView));
|
||||
#endregion
|
||||
|
||||
public PendingConnectionView()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(PendingConnectionView);
|
||||
|
||||
SetupPathData();
|
||||
SetupVisualStateBindings();
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
VisualStateManager.GoToState(this, NonErrorState, false);
|
||||
}
|
||||
|
||||
private void SetupPathData()
|
||||
{
|
||||
this.WhenActivated(d => d(
|
||||
this.WhenAnyValue(v => v.ViewModel.LooseEndPoint)
|
||||
.Select(_ =>
|
||||
{
|
||||
if (ViewModel.Input == null)
|
||||
{
|
||||
return ConnectionView.BuildSmoothBezier(ViewModel.Output.Port.CenterPoint,
|
||||
ViewModel.Output.PortPosition,
|
||||
ViewModel.LooseEndPoint);
|
||||
}
|
||||
else if (ViewModel.Output == null)
|
||||
{
|
||||
return ConnectionView.BuildSmoothBezier(ViewModel.LooseEndPoint,
|
||||
ViewModel.Input.Port.CenterPoint,
|
||||
ViewModel.Input.PortPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ConnectionView.BuildSmoothBezier(ViewModel.Output.Port.CenterPoint,
|
||||
ViewModel.Output.PortPosition,
|
||||
ViewModel.Input.Port.CenterPoint,
|
||||
ViewModel.Input.PortPosition);
|
||||
}
|
||||
})
|
||||
.BindTo(this, v => v.Geometry)
|
||||
));
|
||||
}
|
||||
|
||||
private void SetupVisualStateBindings()
|
||||
{
|
||||
this.WhenActivated(d => d(
|
||||
this.WhenAnyValue(v => v.ViewModel.Validation.IsValid).Subscribe(isValid =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isValid ? NonErrorState : ErrorState, true);
|
||||
})
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
231
intromat/NodeNetwork/Views/PortView.cs
Normal file
231
intromat/NodeNetwork/Views/PortView.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using NodeNetwork.ViewModels;
|
||||
using NodeNetwork.Views.Controls;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace NodeNetwork.Views
|
||||
{
|
||||
[TemplateVisualState(Name = ConnectedState, GroupName = ConnectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = DisconnectedState, GroupName = ConnectedVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = HighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonHighlightedState, GroupName = HighlightVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = ErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
[TemplateVisualState(Name = NonErrorState, GroupName = ErrorVisualStatesGroup)]
|
||||
public class PortView : Control, IViewFor<PortViewModel>
|
||||
{
|
||||
#region ViewModel
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
|
||||
typeof(PortViewModel), typeof(PortView), new PropertyMetadata(null));
|
||||
|
||||
public PortViewModel ViewModel
|
||||
{
|
||||
get => (PortViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (PortViewModel)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ConnectedStates
|
||||
public const string ConnectedVisualStatesGroup = "ConnectedStates";
|
||||
public const string ConnectedState = "Connected";
|
||||
public const string DisconnectedState = "Disconnected";
|
||||
#endregion
|
||||
|
||||
#region HighlightStates
|
||||
public const string HighlightVisualStatesGroup = "HighlightStates";
|
||||
public const string HighlightedState = "Highlighted";
|
||||
public const string NonHighlightedState = "NonHighlighted";
|
||||
#endregion
|
||||
|
||||
#region ErrorStates
|
||||
public const string ErrorVisualStatesGroup = "ErrorStates";
|
||||
public const string ErrorState = "Error";
|
||||
public const string NonErrorState = "NoError";
|
||||
#endregion
|
||||
|
||||
#region Brushes
|
||||
#region RegularStroke
|
||||
public Brush RegularStroke
|
||||
{
|
||||
get => (Brush)this.GetValue(RegularStrokeProperty);
|
||||
set => this.SetValue(RegularStrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty RegularStrokeProperty = DependencyProperty.Register(nameof(RegularStroke), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region RegularFill
|
||||
public Brush RegularFill
|
||||
{
|
||||
get => (Brush)this.GetValue(RegularFillProperty);
|
||||
set => this.SetValue(RegularFillProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty RegularFillProperty = DependencyProperty.Register(nameof(RegularFill), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region ConnectedStroke
|
||||
public Brush ConnectedStroke
|
||||
{
|
||||
get => (Brush)this.GetValue(ConnectedStrokeProperty);
|
||||
set => this.SetValue(ConnectedStrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ConnectedStrokeProperty = DependencyProperty.Register(nameof(ConnectedStroke), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region ConnectedFill
|
||||
public Brush ConnectedFill
|
||||
{
|
||||
get => (Brush)this.GetValue(ConnectedFillProperty);
|
||||
set => this.SetValue(ConnectedFillProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ConnectedFillProperty = DependencyProperty.Register(nameof(ConnectedFill), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region HighlightStroke
|
||||
public Brush HighlightStroke
|
||||
{
|
||||
get => (Brush)this.GetValue(HighlightStrokeProperty);
|
||||
set => this.SetValue(HighlightStrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HighlightStrokeProperty = DependencyProperty.Register(nameof(HighlightStroke), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region HighlightFill
|
||||
public Brush HighlightFill
|
||||
{
|
||||
get => (Brush)this.GetValue(HighlightFillProperty);
|
||||
set => this.SetValue(HighlightFillProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HighlightFillProperty = DependencyProperty.Register(nameof(HighlightFill), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region ErrorStroke
|
||||
public Brush ErrorStroke
|
||||
{
|
||||
get => (Brush)this.GetValue(ErrorStrokeProperty);
|
||||
set => this.SetValue(ErrorStrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ErrorStrokeProperty = DependencyProperty.Register(nameof(ErrorStroke), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
|
||||
#region ErrorFill
|
||||
public Brush ErrorFill
|
||||
{
|
||||
get => (Brush)this.GetValue(ErrorFillProperty);
|
||||
set => this.SetValue(ErrorFillProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ErrorFillProperty = DependencyProperty.Register(nameof(ErrorFill), typeof(Brush), typeof(PortView));
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
public PortView()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(PortView);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
VisualStateManager.GoToState(this, DisconnectedState, false);
|
||||
VisualStateManager.GoToState(this, NonHighlightedState, false);
|
||||
VisualStateManager.GoToState(this, NonErrorState, false);
|
||||
|
||||
SetupLayoutEvent();
|
||||
SetupMouseEvents();
|
||||
SetupVisualStateBindings();
|
||||
}
|
||||
|
||||
private void SetupVisualStateBindings()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.WhenAnyObservable(v => v.ViewModel.Parent.Connections.CountChanged).Select(c => c == 0).Subscribe(isDisconnected =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isDisconnected ? DisconnectedState : ConnectedState, true);
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.IsHighlighted).Subscribe(isHighlighted =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isHighlighted ? HighlightedState : NonHighlightedState, true);
|
||||
}).DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(v => v.ViewModel.IsInErrorMode).Subscribe(isInErrorMode =>
|
||||
{
|
||||
VisualStateManager.GoToState(this, isInErrorMode ? ErrorState : NonErrorState, true);
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void SetupLayoutEvent()
|
||||
{
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
this.Events().LayoutUpdated.Subscribe(e =>
|
||||
{
|
||||
//Update endpoint center point
|
||||
if (ViewModel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkView networkView = WPFUtils.FindParent<NetworkView>(this);
|
||||
if (networkView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Point center = new Point(this.ActualWidth / 2d, this.ActualHeight / 2d);
|
||||
if (Margin.Left < 0)
|
||||
{
|
||||
center.X += Margin.Left;
|
||||
}
|
||||
else if (Margin.Right < 0)
|
||||
{
|
||||
center.X -= Margin.Right;
|
||||
}
|
||||
|
||||
var transform = this.TransformToAncestor(networkView.contentContainer);
|
||||
ViewModel.CenterPoint = transform.Transform(center);
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupMouseEvents()
|
||||
{
|
||||
this.MouseLeftButtonDown += (sender, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
ViewModel.OnDragFromPort();
|
||||
};
|
||||
this.MouseEnter += (sender, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
ViewModel.OnPortEnter();
|
||||
};
|
||||
this.MouseLeave += (sender, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
ViewModel.OnPortLeave();
|
||||
};
|
||||
this.MouseLeftButtonUp += (sender, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
ViewModel.OnDropOnPort();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
intromat/NodeNetwork/bin/Debug/NodeNetwork.6.0.0.nupkg
Normal file
BIN
intromat/NodeNetwork/bin/Debug/NodeNetwork.6.0.0.nupkg
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/NodeNetwork.6.0.0.symbols.nupkg
Normal file
BIN
intromat/NodeNetwork/bin/Debug/NodeNetwork.6.0.0.symbols.nupkg
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/DynamicData.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/DynamicData.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/NodeNetwork.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/NodeNetwork.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/NodeNetwork.pdb
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/NodeNetwork.pdb
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/Pharmacist.Common.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/Pharmacist.Common.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.Events.WPF.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.Events.WPF.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.Wpf.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.Wpf.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/ReactiveUI.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/Splat.Drawing.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/Splat.Drawing.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/Splat.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/Splat.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Buffers.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Buffers.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Memory.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Memory.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Numerics.Vectors.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Numerics.Vectors.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Reactive.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/System.Reactive.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/System.ValueTuple.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/System.ValueTuple.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net48/log4net.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net48/log4net.dll
Normal file
Binary file not shown.
@@ -0,0 +1,519 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v5.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v5.0": {
|
||||
"NodeNetwork/6.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"ReactiveUI": "13.2.18",
|
||||
"ReactiveUI.Events.WPF": "13.2.18",
|
||||
"ReactiveUI.WPF": "13.2.18",
|
||||
"Splat.Drawing": "11.0.1",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Collections.Immutable": "5.0.0",
|
||||
"System.Data.DataSetExtensions": "4.5.0",
|
||||
"System.Drawing.Primitives": "4.3.0",
|
||||
"System.Memory": "4.5.4",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "5.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||
"System.ValueTuple": "4.5.0",
|
||||
"log4net": "2.0.12"
|
||||
},
|
||||
"runtime": {
|
||||
"NodeNetwork.dll": {}
|
||||
}
|
||||
},
|
||||
"DynamicData/7.1.1": {
|
||||
"dependencies": {
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0/DynamicData.dll": {
|
||||
"assemblyVersion": "7.1.0.0",
|
||||
"fileVersion": "7.1.1.11487"
|
||||
}
|
||||
}
|
||||
},
|
||||
"log4net/2.0.12": {
|
||||
"dependencies": {
|
||||
"System.Configuration.ConfigurationManager": "4.5.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/log4net.dll": {
|
||||
"assemblyVersion": "2.0.12.0",
|
||||
"fileVersion": "2.0.12.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {},
|
||||
"Pharmacist.Common/2.0.8": {
|
||||
"dependencies": {
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0/Pharmacist.Common.dll": {
|
||||
"assemblyVersion": "2.0.0.0",
|
||||
"fileVersion": "2.0.8.15338"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI/13.2.18": {
|
||||
"dependencies": {
|
||||
"DynamicData": "7.1.1",
|
||||
"Splat": "11.0.1",
|
||||
"System.Reactive": "5.0.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI.Events.WPF/13.2.18": {
|
||||
"dependencies": {
|
||||
"Pharmacist.Common": "2.0.8",
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.Events.WPF.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI.WPF/13.2.18": {
|
||||
"dependencies": {
|
||||
"ReactiveUI": "13.2.18",
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.Wpf.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Splat/11.0.1": {
|
||||
"runtime": {
|
||||
"lib/net5.0/Splat.dll": {
|
||||
"assemblyVersion": "11.0.0.0",
|
||||
"fileVersion": "11.0.1.61461"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Splat.Drawing/11.0.1": {
|
||||
"dependencies": {
|
||||
"Splat": "11.0.1",
|
||||
"System.Diagnostics.Contracts": "4.3.0",
|
||||
"System.Drawing.Primitives": "4.3.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/Splat.Drawing.dll": {
|
||||
"assemblyVersion": "11.0.0.0",
|
||||
"fileVersion": "11.0.1.61461"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Buffers/4.5.1": {},
|
||||
"System.Collections.Immutable/5.0.0": {},
|
||||
"System.Configuration.ConfigurationManager/4.5.0": {
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.5.0",
|
||||
"System.Security.Permissions": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Data.DataSetExtensions/4.5.0": {},
|
||||
"System.Diagnostics.Contracts/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Drawing.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Memory/4.5.4": {},
|
||||
"System.Numerics.Vectors/4.5.0": {},
|
||||
"System.Reactive/5.0.0": {
|
||||
"runtime": {
|
||||
"lib/net5.0/System.Reactive.dll": {
|
||||
"assemblyVersion": "5.0.0.0",
|
||||
"fileVersion": "5.0.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/5.0.0": {},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"System.Security.Principal.Windows": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.5.0": {},
|
||||
"System.Security.Permissions/4.5.0": {
|
||||
"dependencies": {
|
||||
"System.Security.AccessControl": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.5.4": {},
|
||||
"System.ValueTuple/4.5.0": {}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"NodeNetwork/6.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"DynamicData/7.1.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Pc6J5bFnSxEa64PV2V67FMcLlDdpv6m+zTBKSnRN3aLon/WtWWy8kuDpHFbJlgXHtqc6Nxloj9ItuvDlvKC/8w==",
|
||||
"path": "dynamicdata/7.1.1",
|
||||
"hashPath": "dynamicdata.7.1.1.nupkg.sha512"
|
||||
},
|
||||
"log4net/2.0.12": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-9P67BCftJ7KG+B7rNOM1A9KczUwyEDed6zbAddy5Cj/73xVkzi+rEAHeOgUnW5wDqy1JFlY8+oTP0m1PgJ03Tg==",
|
||||
"path": "log4net/2.0.12",
|
||||
"hashPath": "log4net.2.0.12.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==",
|
||||
"path": "microsoft.csharp/4.7.0",
|
||||
"hashPath": "microsoft.csharp.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==",
|
||||
"path": "microsoft.netcore.platforms/2.0.0",
|
||||
"hashPath": "microsoft.netcore.platforms.2.0.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
|
||||
"path": "microsoft.netcore.targets/1.1.0",
|
||||
"hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"Pharmacist.Common/2.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-NNiYvv2oTd18ckJMBt8zatCBPj0KwbzbxMuxgu45m20VtqvkvR6AborbOhkhmJC70iaSv3uLvhTnFExIJGDnQA==",
|
||||
"path": "pharmacist.common/2.0.8",
|
||||
"hashPath": "pharmacist.common.2.0.8.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-w457p8goRjJgbggK2whtgYO8U9SOT1JbMDyZOKceibWoZVuOGME4RfUc60/AsLVmfwlkI+9ve+xc2S696nJZuQ==",
|
||||
"path": "reactiveui/13.2.18",
|
||||
"hashPath": "reactiveui.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI.Events.WPF/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-m9mFgMdSWFAdlCEFOahD2bfDo+zV8BlLxOhTSVSEFbtiSC0loYHSbJDBZYu/nxTTYzjqHTN86PZ7T9NoRgfVGw==",
|
||||
"path": "reactiveui.events.wpf/13.2.18",
|
||||
"hashPath": "reactiveui.events.wpf.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI.WPF/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ALpQe9Y970v4d/RfFT/keb93POq1WEYwUq0bfvZchUiYG4j8GOcFe085x+D5bfwh2aCRz/hHNl+9fTFVnCRisw==",
|
||||
"path": "reactiveui.wpf/13.2.18",
|
||||
"hashPath": "reactiveui.wpf.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"Splat/11.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-C1p+fZE+xgwKCqnf9Qsk0lrJYGiUplWpS2wp9/RR/YNHkjx7vBCRebau1Uej7ZXda71eJgZVBYzZq0/qsQOc3Q==",
|
||||
"path": "splat/11.0.1",
|
||||
"hashPath": "splat.11.0.1.nupkg.sha512"
|
||||
},
|
||||
"Splat.Drawing/11.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-hSho9yLfiv2+QhWqZImg01lhZZzz/6qPP3r2AQQRRJdxIoqgcgw1VqBWYC5bT+4QzcX/hAcjtpmQXmYEg2KBZw==",
|
||||
"path": "splat.drawing/11.0.1",
|
||||
"hashPath": "splat.drawing.11.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Buffers/4.5.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==",
|
||||
"path": "system.buffers/4.5.1",
|
||||
"hashPath": "system.buffers.4.5.1.nupkg.sha512"
|
||||
},
|
||||
"System.Collections.Immutable/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||
"path": "system.collections.immutable/5.0.0",
|
||||
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-UIFvaFfuKhLr9u5tWMxmVoDPkFeD+Qv8gUuap4aZgVGYSYMdERck4OhLN/2gulAc0nYTEigWXSJNNWshrmxnng==",
|
||||
"path": "system.configuration.configurationmanager/4.5.0",
|
||||
"hashPath": "system.configuration.configurationmanager.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Data.DataSetExtensions/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-221clPs1445HkTBZPL+K9sDBdJRB8UN8rgjO3ztB0CQ26z//fmJXtlsr6whGatscsKGBrhJl5bwJuKSA8mwFOw==",
|
||||
"path": "system.data.datasetextensions/4.5.0",
|
||||
"hashPath": "system.data.datasetextensions.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Contracts/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-eelRRbnm+OloiQvp9CXS0ixjNQldjjkHO4iIkR5XH2VIP8sUB/SIpa1TdUW6/+HDcQ+MlhP3pNa1u5SbzYuWGA==",
|
||||
"path": "system.diagnostics.contracts/4.3.0",
|
||||
"hashPath": "system.diagnostics.contracts.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Drawing.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-1QU/c35gwdhvj77fkScXQQbjiVAqIL3fEYn/19NE0CV/ic5TN5PyWAft8HsrbRd4SBLEoErNCkWSzMDc0MmbRw==",
|
||||
"path": "system.drawing.primitives/4.3.0",
|
||||
"hashPath": "system.drawing.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
|
||||
"path": "system.globalization/4.3.0",
|
||||
"hashPath": "system.globalization.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
|
||||
"path": "system.io/4.3.0",
|
||||
"hashPath": "system.io.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Memory/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
|
||||
"path": "system.memory/4.5.4",
|
||||
"hashPath": "system.memory.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"System.Numerics.Vectors/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==",
|
||||
"path": "system.numerics.vectors/4.5.0",
|
||||
"hashPath": "system.numerics.vectors.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reactive/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"path": "system.reactive/5.0.0",
|
||||
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
|
||||
"path": "system.reflection/4.3.0",
|
||||
"hashPath": "system.reflection.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
|
||||
"path": "system.reflection.primitives/4.3.0",
|
||||
"hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
|
||||
"path": "system.resources.resourcemanager/4.3.0",
|
||||
"hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
|
||||
"path": "system.runtime/4.3.0",
|
||||
"hashPath": "system.runtime.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==",
|
||||
"path": "system.runtime.compilerservices.unsafe/5.0.0",
|
||||
"hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
|
||||
"path": "system.runtime.extensions/4.3.0",
|
||||
"hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==",
|
||||
"path": "system.runtime.serialization.primitives/4.3.0",
|
||||
"hashPath": "system.runtime.serialization.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==",
|
||||
"path": "system.security.accesscontrol/4.5.0",
|
||||
"hashPath": "system.security.accesscontrol.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==",
|
||||
"path": "system.security.cryptography.protecteddata/4.5.0",
|
||||
"hashPath": "system.security.cryptography.protecteddata.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Permissions/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==",
|
||||
"path": "system.security.permissions/4.5.0",
|
||||
"hashPath": "system.security.permissions.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==",
|
||||
"path": "system.security.principal.windows/4.5.0",
|
||||
"hashPath": "system.security.principal.windows.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
|
||||
"path": "system.text.encoding/4.3.0",
|
||||
"hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
|
||||
"path": "system.threading.tasks/4.3.0",
|
||||
"hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"path": "system.threading.tasks.extensions/4.5.4",
|
||||
"hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"System.ValueTuple/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||
"path": "system.valuetuple/4.5.0",
|
||||
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
intromat/NodeNetwork/bin/Debug/net5.0-windows7.0/NodeNetwork.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net5.0-windows7.0/NodeNetwork.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net5.0-windows7.0/NodeNetwork.pdb
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net5.0-windows7.0/NodeNetwork.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,519 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v7.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v7.0": {
|
||||
"NodeNetwork/6.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"ReactiveUI": "13.2.18",
|
||||
"ReactiveUI.Events.WPF": "13.2.18",
|
||||
"ReactiveUI.WPF": "13.2.18",
|
||||
"Splat.Drawing": "11.0.1",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Collections.Immutable": "5.0.0",
|
||||
"System.Data.DataSetExtensions": "4.5.0",
|
||||
"System.Drawing.Primitives": "4.3.0",
|
||||
"System.Memory": "4.5.4",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "5.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||
"System.ValueTuple": "4.5.0",
|
||||
"log4net": "2.0.12"
|
||||
},
|
||||
"runtime": {
|
||||
"NodeNetwork.dll": {}
|
||||
}
|
||||
},
|
||||
"DynamicData/7.1.1": {
|
||||
"dependencies": {
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0/DynamicData.dll": {
|
||||
"assemblyVersion": "7.1.0.0",
|
||||
"fileVersion": "7.1.1.11487"
|
||||
}
|
||||
}
|
||||
},
|
||||
"log4net/2.0.12": {
|
||||
"dependencies": {
|
||||
"System.Configuration.ConfigurationManager": "4.5.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/log4net.dll": {
|
||||
"assemblyVersion": "2.0.12.0",
|
||||
"fileVersion": "2.0.12.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {},
|
||||
"Pharmacist.Common/2.0.8": {
|
||||
"dependencies": {
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0/Pharmacist.Common.dll": {
|
||||
"assemblyVersion": "2.0.0.0",
|
||||
"fileVersion": "2.0.8.15338"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI/13.2.18": {
|
||||
"dependencies": {
|
||||
"DynamicData": "7.1.1",
|
||||
"Splat": "11.0.1",
|
||||
"System.Reactive": "5.0.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI.Events.WPF/13.2.18": {
|
||||
"dependencies": {
|
||||
"Pharmacist.Common": "2.0.8",
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.Events.WPF.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactiveUI.WPF/13.2.18": {
|
||||
"dependencies": {
|
||||
"ReactiveUI": "13.2.18",
|
||||
"System.Reactive": "5.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/ReactiveUI.Wpf.dll": {
|
||||
"assemblyVersion": "13.2.0.0",
|
||||
"fileVersion": "13.2.18.42750"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Splat/11.0.1": {
|
||||
"runtime": {
|
||||
"lib/net5.0/Splat.dll": {
|
||||
"assemblyVersion": "11.0.0.0",
|
||||
"fileVersion": "11.0.1.61461"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Splat.Drawing/11.0.1": {
|
||||
"dependencies": {
|
||||
"Splat": "11.0.1",
|
||||
"System.Diagnostics.Contracts": "4.3.0",
|
||||
"System.Drawing.Primitives": "4.3.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0-windows7.0/Splat.Drawing.dll": {
|
||||
"assemblyVersion": "11.0.0.0",
|
||||
"fileVersion": "11.0.1.61461"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Buffers/4.5.1": {},
|
||||
"System.Collections.Immutable/5.0.0": {},
|
||||
"System.Configuration.ConfigurationManager/4.5.0": {
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.5.0",
|
||||
"System.Security.Permissions": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Data.DataSetExtensions/4.5.0": {},
|
||||
"System.Diagnostics.Contracts/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Drawing.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Memory/4.5.4": {},
|
||||
"System.Numerics.Vectors/4.5.0": {},
|
||||
"System.Reactive/5.0.0": {
|
||||
"runtime": {
|
||||
"lib/net5.0/System.Reactive.dll": {
|
||||
"assemblyVersion": "5.0.0.0",
|
||||
"fileVersion": "5.0.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/5.0.0": {},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"System.Security.Principal.Windows": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.5.0": {},
|
||||
"System.Security.Permissions/4.5.0": {
|
||||
"dependencies": {
|
||||
"System.Security.AccessControl": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.5.4": {},
|
||||
"System.ValueTuple/4.5.0": {}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"NodeNetwork/6.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"DynamicData/7.1.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Pc6J5bFnSxEa64PV2V67FMcLlDdpv6m+zTBKSnRN3aLon/WtWWy8kuDpHFbJlgXHtqc6Nxloj9ItuvDlvKC/8w==",
|
||||
"path": "dynamicdata/7.1.1",
|
||||
"hashPath": "dynamicdata.7.1.1.nupkg.sha512"
|
||||
},
|
||||
"log4net/2.0.12": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-9P67BCftJ7KG+B7rNOM1A9KczUwyEDed6zbAddy5Cj/73xVkzi+rEAHeOgUnW5wDqy1JFlY8+oTP0m1PgJ03Tg==",
|
||||
"path": "log4net/2.0.12",
|
||||
"hashPath": "log4net.2.0.12.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==",
|
||||
"path": "microsoft.csharp/4.7.0",
|
||||
"hashPath": "microsoft.csharp.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==",
|
||||
"path": "microsoft.netcore.platforms/2.0.0",
|
||||
"hashPath": "microsoft.netcore.platforms.2.0.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
|
||||
"path": "microsoft.netcore.targets/1.1.0",
|
||||
"hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"Pharmacist.Common/2.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-NNiYvv2oTd18ckJMBt8zatCBPj0KwbzbxMuxgu45m20VtqvkvR6AborbOhkhmJC70iaSv3uLvhTnFExIJGDnQA==",
|
||||
"path": "pharmacist.common/2.0.8",
|
||||
"hashPath": "pharmacist.common.2.0.8.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-w457p8goRjJgbggK2whtgYO8U9SOT1JbMDyZOKceibWoZVuOGME4RfUc60/AsLVmfwlkI+9ve+xc2S696nJZuQ==",
|
||||
"path": "reactiveui/13.2.18",
|
||||
"hashPath": "reactiveui.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI.Events.WPF/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-m9mFgMdSWFAdlCEFOahD2bfDo+zV8BlLxOhTSVSEFbtiSC0loYHSbJDBZYu/nxTTYzjqHTN86PZ7T9NoRgfVGw==",
|
||||
"path": "reactiveui.events.wpf/13.2.18",
|
||||
"hashPath": "reactiveui.events.wpf.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"ReactiveUI.WPF/13.2.18": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ALpQe9Y970v4d/RfFT/keb93POq1WEYwUq0bfvZchUiYG4j8GOcFe085x+D5bfwh2aCRz/hHNl+9fTFVnCRisw==",
|
||||
"path": "reactiveui.wpf/13.2.18",
|
||||
"hashPath": "reactiveui.wpf.13.2.18.nupkg.sha512"
|
||||
},
|
||||
"Splat/11.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-C1p+fZE+xgwKCqnf9Qsk0lrJYGiUplWpS2wp9/RR/YNHkjx7vBCRebau1Uej7ZXda71eJgZVBYzZq0/qsQOc3Q==",
|
||||
"path": "splat/11.0.1",
|
||||
"hashPath": "splat.11.0.1.nupkg.sha512"
|
||||
},
|
||||
"Splat.Drawing/11.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-hSho9yLfiv2+QhWqZImg01lhZZzz/6qPP3r2AQQRRJdxIoqgcgw1VqBWYC5bT+4QzcX/hAcjtpmQXmYEg2KBZw==",
|
||||
"path": "splat.drawing/11.0.1",
|
||||
"hashPath": "splat.drawing.11.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Buffers/4.5.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==",
|
||||
"path": "system.buffers/4.5.1",
|
||||
"hashPath": "system.buffers.4.5.1.nupkg.sha512"
|
||||
},
|
||||
"System.Collections.Immutable/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||
"path": "system.collections.immutable/5.0.0",
|
||||
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-UIFvaFfuKhLr9u5tWMxmVoDPkFeD+Qv8gUuap4aZgVGYSYMdERck4OhLN/2gulAc0nYTEigWXSJNNWshrmxnng==",
|
||||
"path": "system.configuration.configurationmanager/4.5.0",
|
||||
"hashPath": "system.configuration.configurationmanager.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Data.DataSetExtensions/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-221clPs1445HkTBZPL+K9sDBdJRB8UN8rgjO3ztB0CQ26z//fmJXtlsr6whGatscsKGBrhJl5bwJuKSA8mwFOw==",
|
||||
"path": "system.data.datasetextensions/4.5.0",
|
||||
"hashPath": "system.data.datasetextensions.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Contracts/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-eelRRbnm+OloiQvp9CXS0ixjNQldjjkHO4iIkR5XH2VIP8sUB/SIpa1TdUW6/+HDcQ+MlhP3pNa1u5SbzYuWGA==",
|
||||
"path": "system.diagnostics.contracts/4.3.0",
|
||||
"hashPath": "system.diagnostics.contracts.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Drawing.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-1QU/c35gwdhvj77fkScXQQbjiVAqIL3fEYn/19NE0CV/ic5TN5PyWAft8HsrbRd4SBLEoErNCkWSzMDc0MmbRw==",
|
||||
"path": "system.drawing.primitives/4.3.0",
|
||||
"hashPath": "system.drawing.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
|
||||
"path": "system.globalization/4.3.0",
|
||||
"hashPath": "system.globalization.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
|
||||
"path": "system.io/4.3.0",
|
||||
"hashPath": "system.io.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Memory/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
|
||||
"path": "system.memory/4.5.4",
|
||||
"hashPath": "system.memory.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"System.Numerics.Vectors/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==",
|
||||
"path": "system.numerics.vectors/4.5.0",
|
||||
"hashPath": "system.numerics.vectors.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reactive/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"path": "system.reactive/5.0.0",
|
||||
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
|
||||
"path": "system.reflection/4.3.0",
|
||||
"hashPath": "system.reflection.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
|
||||
"path": "system.reflection.primitives/4.3.0",
|
||||
"hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
|
||||
"path": "system.resources.resourcemanager/4.3.0",
|
||||
"hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
|
||||
"path": "system.runtime/4.3.0",
|
||||
"hashPath": "system.runtime.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/5.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==",
|
||||
"path": "system.runtime.compilerservices.unsafe/5.0.0",
|
||||
"hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
|
||||
"path": "system.runtime.extensions/4.3.0",
|
||||
"hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==",
|
||||
"path": "system.runtime.serialization.primitives/4.3.0",
|
||||
"hashPath": "system.runtime.serialization.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==",
|
||||
"path": "system.security.accesscontrol/4.5.0",
|
||||
"hashPath": "system.security.accesscontrol.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==",
|
||||
"path": "system.security.cryptography.protecteddata/4.5.0",
|
||||
"hashPath": "system.security.cryptography.protecteddata.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Permissions/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==",
|
||||
"path": "system.security.permissions/4.5.0",
|
||||
"hashPath": "system.security.permissions.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==",
|
||||
"path": "system.security.principal.windows/4.5.0",
|
||||
"hashPath": "system.security.principal.windows.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
|
||||
"path": "system.text.encoding/4.3.0",
|
||||
"hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
|
||||
"path": "system.threading.tasks/4.3.0",
|
||||
"hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"path": "system.threading.tasks.extensions/4.5.4",
|
||||
"hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"System.ValueTuple/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||
"path": "system.valuetuple/4.5.0",
|
||||
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
intromat/NodeNetwork/bin/Debug/net7.0-windows7.0/NodeNetwork.dll
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net7.0-windows7.0/NodeNetwork.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/bin/Debug/net7.0-windows7.0/NodeNetwork.pdb
Normal file
BIN
intromat/NodeNetwork/bin/Debug/net7.0-windows7.0/NodeNetwork.pdb
Normal file
Binary file not shown.
62
intromat/NodeNetwork/obj/Debug/NodeNetwork.6.0.0.nuspec
Normal file
62
intromat/NodeNetwork/obj/Debug/NodeNetwork.6.0.0.nuspec
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>NodeNetwork</id>
|
||||
<version>6.0.0</version>
|
||||
<authors>Wouter De Keersmaecker</authors>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<licenseUrl>https://licenses.nuget.org/Apache-2.0</licenseUrl>
|
||||
<description>Package Description</description>
|
||||
<tags>wpf reactiveui node network editor node-editor graph</tags>
|
||||
<repository type="Github" url="https://www.github.com/wouterdek/nodenetwork" />
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.8">
|
||||
<dependency id="Microsoft.CSharp" version="4.7.0" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.Events.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="Splat.Drawing" version="11.0.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Buffers" version="4.5.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Collections.Immutable" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Data.DataSetExtensions" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Primitives" version="4.3.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Memory" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Numerics.Vectors" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="log4net" version="2.0.12" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework="net7.0-windows7.0">
|
||||
<dependency id="Microsoft.CSharp" version="4.7.0" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.Events.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="Splat.Drawing" version="11.0.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Buffers" version="4.5.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Collections.Immutable" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Data.DataSetExtensions" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Primitives" version="4.3.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Memory" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Numerics.Vectors" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="log4net" version="2.0.12" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
<frameworkReferences>
|
||||
<group targetFramework="net7.0-windows7.0">
|
||||
<frameworkReference name="Microsoft.WindowsDesktop.App.WPF" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.8" />
|
||||
</frameworkReferences>
|
||||
<frameworkAssemblies>
|
||||
<frameworkAssembly assemblyName="System.Drawing.Primitives" targetFramework=".NETFramework4.8" />
|
||||
</frameworkAssemblies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\NodeNetwork.dll" target="lib\net48\NodeNetwork.dll" />
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net7.0-windows7.0\NodeNetwork.dll" target="lib\net7.0-windows7.0\NodeNetwork.dll" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>NodeNetwork</id>
|
||||
<version>6.0.0</version>
|
||||
<authors>Wouter De Keersmaecker</authors>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<licenseUrl>https://licenses.nuget.org/Apache-2.0</licenseUrl>
|
||||
<description>Package Description</description>
|
||||
<tags>wpf reactiveui node network editor node-editor graph</tags>
|
||||
<repository type="Github" url="https://www.github.com/wouterdek/nodenetwork" />
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.8">
|
||||
<dependency id="Microsoft.CSharp" version="4.7.0" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.Events.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="Splat.Drawing" version="11.0.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Buffers" version="4.5.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Collections.Immutable" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Data.DataSetExtensions" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Primitives" version="4.3.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Memory" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Numerics.Vectors" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="log4net" version="2.0.12" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework="net7.0-windows7.0">
|
||||
<dependency id="Microsoft.CSharp" version="4.7.0" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.Events.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="ReactiveUI.WPF" version="13.2.18" exclude="Build,Analyzers" />
|
||||
<dependency id="Splat.Drawing" version="11.0.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Buffers" version="4.5.1" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Collections.Immutable" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Data.DataSetExtensions" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Drawing.Primitives" version="4.3.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Memory" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Numerics.Vectors" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
|
||||
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
|
||||
<dependency id="log4net" version="2.0.12" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
<frameworkReferences>
|
||||
<group targetFramework="net7.0-windows7.0">
|
||||
<frameworkReference name="Microsoft.WindowsDesktop.App.WPF" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.8" />
|
||||
</frameworkReferences>
|
||||
<frameworkAssemblies>
|
||||
<frameworkAssembly assemblyName="System.Drawing.Primitives" targetFramework=".NETFramework4.8" />
|
||||
</frameworkAssemblies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\NodeNetwork.pdb" target="lib\net48\NodeNetwork.pdb" />
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net7.0-windows7.0\NodeNetwork.pdb" target="lib\net7.0-windows7.0\NodeNetwork.pdb" />
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\NodeNetwork.dll" target="lib\net48\NodeNetwork.dll" />
|
||||
<file src="E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net7.0-windows7.0\NodeNetwork.dll" target="lib\net7.0-windows7.0\NodeNetwork.dll" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
|
||||
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace XamlGeneratedNamespace {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GeneratedInternalTypeHelper
|
||||
/// </summary>
|
||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.3.0")]
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper {
|
||||
|
||||
/// <summary>
|
||||
/// CreateInstance
|
||||
/// </summary>
|
||||
protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) {
|
||||
return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
|
||||
| (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetPropertyValue
|
||||
/// </summary>
|
||||
protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) {
|
||||
return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetPropertyValue
|
||||
/// </summary>
|
||||
protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) {
|
||||
propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CreateDelegate
|
||||
/// </summary>
|
||||
protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) {
|
||||
return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod
|
||||
| (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] {
|
||||
delegateType,
|
||||
handler}, null)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AddEventHandler
|
||||
/// </summary>
|
||||
protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) {
|
||||
eventInfo.AddEventHandler(target, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace XamlGeneratedNamespace {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GeneratedInternalTypeHelper
|
||||
/// </summary>
|
||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.3.0")]
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper {
|
||||
|
||||
/// <summary>
|
||||
/// CreateInstance
|
||||
/// </summary>
|
||||
protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) {
|
||||
return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
|
||||
| (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetPropertyValue
|
||||
/// </summary>
|
||||
protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) {
|
||||
return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetPropertyValue
|
||||
/// </summary>
|
||||
protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) {
|
||||
propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CreateDelegate
|
||||
/// </summary>
|
||||
protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) {
|
||||
return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod
|
||||
| (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] {
|
||||
delegateType,
|
||||
handler}, null)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AddEventHandler
|
||||
/// </summary>
|
||||
protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) {
|
||||
eventInfo.AddEventHandler(target, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
is_global = true
|
||||
build_property.RootNamespace = NodeNetwork
|
||||
build_property.ProjectDir = E:\p4\bluflame\intromat\NodeNetwork\
|
||||
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.assets.cache
Normal file
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.assets.cache
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
1b698fd39048a6f5ebb757d661607b83d59dea23
|
||||
@@ -0,0 +1,45 @@
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\NodeNetwork.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\NodeNetwork.pdb
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\DynamicData.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\log4net.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\Pharmacist.Common.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\ReactiveUI.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\ReactiveUI.Events.WPF.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\ReactiveUI.Wpf.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\Splat.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\Splat.Drawing.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Buffers.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Collections.Immutable.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Memory.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Numerics.Vectors.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Reactive.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Runtime.CompilerServices.Unsafe.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.Threading.Tasks.Extensions.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\bin\Debug\net48\System.ValueTuple.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\Generic.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\Controls\ArrowToggleButton.g.cs
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\Controls\ViewModelViewHostNoAnimations.g.cs
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\NetworkView.g.cs
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\GeneratedInternalTypeHelper.g.cs
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork_MarkupCompile.cache
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork_MarkupCompile.lref
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\ConnectionView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\Endpoint.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\EndpointGroupView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\ErrorMessageView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\NodeEndpointEditorView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\NodeInputView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\NodeOutputView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\NodeView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\PendingConnectionView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Themes\PortView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\Controls\ArrowToggleButton.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\Controls\ViewModelViewHostNoAnimations.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\Views\NetworkView.baml
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.g.resources
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.csproj.CoreCompileInputs.cache
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.csproj.CopyComplete
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.dll
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.pdb
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.csproj.AssemblyReference.cache
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\NodeNetwork.GeneratedMSBuildEditorConfig.editorconfig
|
||||
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.dll
Normal file
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.dll
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.g.resources
Normal file
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.g.resources
Normal file
Binary file not shown.
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.pdb
Normal file
BIN
intromat/NodeNetwork/obj/Debug/net48/NodeNetwork.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
is_global = true
|
||||
build_property.RootNamespace = NodeNetwork_2v5vgb3o_wpftmp
|
||||
build_property.ProjectDir = E:\p4\bluflame\intromat\NodeNetwork\
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
NodeNetwork
|
||||
|
||||
|
||||
library
|
||||
C#
|
||||
.cs
|
||||
E:\p4\bluflame\intromat\NodeNetwork\obj\Debug\net48\
|
||||
NodeNetwork
|
||||
none
|
||||
false
|
||||
TRACE;DEBUG;NETFRAMEWORK;NET48;
|
||||
|
||||
14-663422403
|
||||
|
||||
39-781031003
|
||||
431661498142
|
||||
Themes\ConnectionView.xaml;Themes\Endpoint.xaml;Themes\EndpointGroupView.xaml;Themes\ErrorMessageView.xaml;Themes\Generic.xaml;Themes\NodeEndpointEditorView.xaml;Themes\NodeInputView.xaml;Themes\NodeOutputView.xaml;Themes\NodeView.xaml;Themes\PendingConnectionView.xaml;Themes\PortView.xaml;Views\Controls\ArrowToggleButton.xaml;Views\Controls\ViewModelViewHostNoAnimations.xaml;Views\NetworkView.xaml;
|
||||
|
||||
False
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user