diff --git a/OctoPatch.sln b/OctoPatch.sln
index 97ec5b0..fc91a46 100644
--- a/OctoPatch.sln
+++ b/OctoPatch.sln
@@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OctoPatch.Plugin.Keyboard",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OctoPatch.Plugin.Rest", "src\Plugins\OctoPatch.Plugin.Rest\OctoPatch.Plugin.Rest.csproj", "{35E27930-07AA-4AE2-999E-E6BBE4B71DFB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OctoPatch.Server.Test", "test\OctoPatch.Server.Test\OctoPatch.Server.Test.csproj", "{91546803-665C-4CC1-B849-8498947F5186}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -81,6 +83,10 @@ Global
{35E27930-07AA-4AE2-999E-E6BBE4B71DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35E27930-07AA-4AE2-999E-E6BBE4B71DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35E27930-07AA-4AE2-999E-E6BBE4B71DFB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91546803-665C-4CC1-B849-8498947F5186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {91546803-665C-4CC1-B849-8498947F5186}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91546803-665C-4CC1-B849-8498947F5186}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {91546803-665C-4CC1-B849-8498947F5186}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -93,6 +99,7 @@ Global
{DBA37B79-AF44-4C21-8BD6-B7704BD339F5} = {FA7B21A1-3ADA-4C35-BF59-100BFD2A689D}
{DD956A0D-1556-4CCA-B1F3-4010D0F0F8F3} = {826BC5FD-CEF2-466A-88E5-55489BDAD44B}
{35E27930-07AA-4AE2-999E-E6BBE4B71DFB} = {826BC5FD-CEF2-466A-88E5-55489BDAD44B}
+ {91546803-665C-4CC1-B849-8498947F5186} = {FA7B21A1-3ADA-4C35-BF59-100BFD2A689D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8F9B99B3-F5BE-4428-9751-1CC99FA5761B}
diff --git a/src/Applications/OctoPatch.DesktopClient/ConfigurationMap.cs b/src/Applications/OctoPatch.DesktopClient/ConfigurationMap.cs
new file mode 100644
index 0000000..6323640
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/ConfigurationMap.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using OctoPatch.DesktopClient.Models;
+using System.Reflection;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace OctoPatch.DesktopClient
+{
+ ///
+ /// Central place to map configuration setup (node/adapter key to configuration model and configuration view)
+ ///
+ public sealed class ConfigurationMap
+ {
+ ///
+ /// Holds the current map
+ ///
+ private static readonly List Map = new List();
+
+ ///
+ /// Constructor scans for existing configuration map attributes within the current app domain
+ ///
+ static ConfigurationMap()
+ {
+ // Scan all referenced assemblies
+ foreach (var assemblies in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ try
+ {
+ // Scan all types
+ foreach (var type in assemblies.GetTypes())
+ {
+ // Scan all existing attributes
+ foreach (var attribute in type.GetCustomAttributes())
+ {
+ Map.Add(new MapEntry(attribute.Key, attribute.ModelType, type));
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // Some assemblies are not allowed to be reflected...?
+ }
+ }
+ }
+
+ ///
+ /// Returns a new instance of the configuration model fitting to the given key or null, when no key is registered
+ ///
+ /// node key
+ /// new model instance
+ public static ConfigurationModel GetConfigurationModel(string key)
+ {
+ var entry = Map.FirstOrDefault(e => string.Equals(e.Key, key, StringComparison.InvariantCultureIgnoreCase));
+ return entry == null ? null : (ConfigurationModel)Activator.CreateInstance(entry.ModelType);
+ }
+
+ public static UserControl GetConfigurationView(ConfigurationModel model)
+ {
+ if (model == null)
+ {
+ return null;
+ }
+
+ var entry = Map.FirstOrDefault(e => e.ModelType == model.GetType());
+ if (entry == null)
+ {
+ return null;
+ }
+
+ var control = (UserControl) Activator.CreateInstance(entry.ViewType);
+
+ // Set data context if possible
+ if (control != null)
+ {
+ control.DataContext = model;
+ }
+
+ return control;
+ }
+
+ #region nested types
+
+ ///
+ /// Local container to store a map entry
+ ///
+ private class MapEntry
+ {
+ ///
+ /// Gets the type of the data model
+ ///
+ public Type ModelType { get; }
+
+ ///
+ /// Gets the type of the view
+ ///
+ public Type ViewType { get; }
+
+ ///
+ /// Gets the key of the node or adapter
+ ///
+ public string Key { get; }
+
+ public MapEntry(string key, Type modelType, Type viewType)
+ {
+ Key = key;
+ ModelType = modelType;
+ ViewType = viewType;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/ConfigurationMapAttribute.cs b/src/Applications/OctoPatch.DesktopClient/ConfigurationMapAttribute.cs
new file mode 100644
index 0000000..7b70fcc
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/ConfigurationMapAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace OctoPatch.DesktopClient
+{
+ ///
+ /// Attribute to decorate the configuration view with
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
+ public sealed class ConfigurationMapAttribute : Attribute
+ {
+ ///
+ /// Gets the key string for the node or adapter
+ ///
+ public string Key { get; }
+
+ ///
+ /// Gets the model type which handles the node or adapter settings
+ ///
+ public Type ModelType { get; }
+
+ public ConfigurationMapAttribute(string key, Type modelType)
+ {
+ Key = key;
+ ModelType = modelType;
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Converters/ConnectorToVisibilityConverter.cs b/src/Applications/OctoPatch.DesktopClient/Converters/ConnectorToVisibilityConverter.cs
deleted file mode 100644
index a42dd2f..0000000
--- a/src/Applications/OctoPatch.DesktopClient/Converters/ConnectorToVisibilityConverter.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using System.Globalization;
-using System.Windows;
-using System.Windows.Data;
-using OctoPatch.DesktopClient.Models;
-
-namespace OctoPatch.DesktopClient.Converters
-{
- [ValueConversion(typeof(NodeModel), typeof(Visibility))]
- public sealed class ConnectorToVisibilityConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- return value is InputNodeModel || value is OutputNodeModel ? Visibility.Visible : Visibility.Collapsed;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/src/Applications/OctoPatch.DesktopClient/Converters/InRangeToVisibilityConverter.cs b/src/Applications/OctoPatch.DesktopClient/Converters/InRangeToVisibilityConverter.cs
new file mode 100644
index 0000000..891cb5a
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Converters/InRangeToVisibilityConverter.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace OctoPatch.DesktopClient.Converters
+{
+ ///
+ /// Checks if the given value is within the range
+ ///
+ [ValueConversion(typeof(int), typeof(Visibility))]
+ public sealed class InRangeToVisibilityConverter : IValueConverter
+ {
+ ///
+ /// Minimum value
+ ///
+ public int MinValue { get; set; }
+
+ ///
+ /// Maximum value
+ ///
+ public int MaxValue { get; set; }
+
+ public InRangeToVisibilityConverter()
+ {
+ MinValue = int.MinValue;
+ MaxValue = int.MaxValue;
+ }
+
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (!(value is int input))
+ {
+ return Visibility.Collapsed;
+ }
+
+ return input >= MinValue && input <= MaxValue ? Visibility.Visible : Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Converters/NodeToVisibilityConverter.cs b/src/Applications/OctoPatch.DesktopClient/Converters/NodeToVisibilityConverter.cs
index ac1ac6e..2159a0c 100644
--- a/src/Applications/OctoPatch.DesktopClient/Converters/NodeToVisibilityConverter.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Converters/NodeToVisibilityConverter.cs
@@ -6,12 +6,87 @@
namespace OctoPatch.DesktopClient.Converters
{
+ ///
+ /// Converts selected tree node type into visibility
+ ///
[ValueConversion(typeof(NodeModel), typeof(Visibility))]
class NodeToVisibilityConverter : IValueConverter
{
+ ///
+ /// show up when common node is selected
+ ///
+ public bool CommonNode { get; set; }
+
+ ///
+ /// show up when attached node is selected
+ ///
+ public bool AttachedNode { get; set; }
+
+ ///
+ /// show up when splitter node is selected
+ ///
+ public bool SplitterNode { get; set; }
+
+ ///
+ /// show up when collector node is selected
+ ///
+ public bool CollectorNode { get; set; }
+
+ ///
+ /// show up when input connector is selected
+ ///
+ public bool InputConnector { get; set; }
+
+ ///
+ /// show up when output connector is selected
+ ///
+ public bool OutputConnector { get; set; }
+
+ ///
+ /// show up when wire is selected
+ ///
+ public bool Wire { get; set; }
+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- return value is CommonNodeModel || value is AttachedNodeModel || value is SplitterNodeModel || value is CollectorNodeModel ? Visibility.Visible : Visibility.Collapsed;
+ var visible = false;
+
+ if (CommonNode && value is CommonNodeModel)
+ {
+ visible = true;
+ }
+
+ if (AttachedNode && value is AttachedNodeModel)
+ {
+ visible = true;
+ }
+
+ if (SplitterNode && value is SplitterNodeModel)
+ {
+ visible = true;
+ }
+
+ if (CollectorNode && value is CollectorNodeModel)
+ {
+ visible = true;
+ }
+
+ if (InputConnector && value is InputNodeModel)
+ {
+ visible = true;
+ }
+
+ if (OutputConnector && value is OutputNodeModel)
+ {
+ visible = true;
+ }
+
+ if (Wire && value is WireNodeModel)
+ {
+ visible = true;
+ }
+
+ return visible ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/src/Applications/OctoPatch.DesktopClient/MainWindow.xaml b/src/Applications/OctoPatch.DesktopClient/MainWindow.xaml
index 6cb46a1..7b7cd36 100644
--- a/src/Applications/OctoPatch.DesktopClient/MainWindow.xaml
+++ b/src/Applications/OctoPatch.DesktopClient/MainWindow.xaml
@@ -6,7 +6,5 @@
xmlns:views="clr-namespace:OctoPatch.DesktopClient.Views"
mc:Ignorable="d"
Title="OctoPatch Desktop" Height="700" Width="800">
-
-
-
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/AdapterConfigurationModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/AdapterConfigurationModel.cs
new file mode 100644
index 0000000..aa21899
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/AdapterConfigurationModel.cs
@@ -0,0 +1,38 @@
+using Newtonsoft.Json;
+
+namespace OctoPatch.DesktopClient.Models
+{
+ ///
+ /// Basic configuration type for node configuration
+ ///
+ /// model type for configuration
+ /// model type for environment
+ public abstract class AdapterConfigurationModel : ConfigurationModel
+ where TConfiguration : IConfiguration
+ where TEnvironment : IEnvironment
+ {
+ public override void Setup(string environment)
+ {
+ // Do nothing since adapter do not have any environment yet
+ }
+
+ public override void SetConfiguration(string configuration)
+ {
+ if (configuration == null)
+ {
+ return;
+ }
+
+ OnSetConfiguration(JsonConvert.DeserializeObject(configuration));
+ }
+
+ protected abstract void OnSetConfiguration(TConfiguration configuration);
+
+ public override string GetConfiguration()
+ {
+ return JsonConvert.SerializeObject(OnGetConfiguration());
+ }
+
+ protected abstract TConfiguration OnGetConfiguration();
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/ConfigurationModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/ConfigurationModel.cs
new file mode 100644
index 0000000..098db3d
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/ConfigurationModel.cs
@@ -0,0 +1,27 @@
+namespace OctoPatch.DesktopClient.Models
+{
+ ///
+ /// Basic type for all kind of configuration models
+ ///
+ public abstract class ConfigurationModel : Model
+ {
+ ///
+ /// Method to apply environment to the configuration model
+ ///
+ /// serialized environment
+ public abstract void Setup(string environment);
+
+ ///
+ /// Method to apply configuration to the configuration model
+ ///
+ /// serialized configuration
+ public abstract void SetConfiguration(string configuration);
+
+ ///
+ /// Method to grab the configuration back in serialized format
+ ///
+ /// serialized configuration
+ public abstract string GetConfiguration();
+
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/KeyboardStringModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/KeyboardStringModel.cs
new file mode 100644
index 0000000..bda6ba7
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/KeyboardStringModel.cs
@@ -0,0 +1,40 @@
+using OctoPatch.Plugin.Keyboard;
+
+namespace OctoPatch.DesktopClient.Models
+{
+ public sealed class KeyboardStringModel : NodeConfigurationModel
+ {
+ private bool _ignoreNotPrintable;
+
+ ///
+ /// Ignores not printable character like whitespace and newline
+ ///
+ public bool IgnoreNotPrintable
+ {
+ get => _ignoreNotPrintable;
+ set
+ {
+ _ignoreNotPrintable = value;
+ OnPropertyChanged();
+ }
+ }
+
+ protected override void OnSetup(EmptyEnvironment environment)
+ {
+
+ }
+
+ protected override KeyboardStringConfiguration OnGetConfiguration()
+ {
+ return new KeyboardStringConfiguration
+ {
+ IgnoreNotPrintable = IgnoreNotPrintable
+ };
+ }
+
+ protected override void OnSetConfiguration(KeyboardStringConfiguration configuration)
+ {
+ IgnoreNotPrintable = configuration.IgnoreNotPrintable;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/LinearAdapterModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/LinearAdapterModel.cs
new file mode 100644
index 0000000..4710d67
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/LinearAdapterModel.cs
@@ -0,0 +1,34 @@
+using System.Windows.Markup;
+using OctoPatch.Core.Adapters;
+
+namespace OctoPatch.DesktopClient.Models
+{
+ public sealed class LinearAdapterModel : AdapterConfigurationModel
+ {
+ private bool _inverted;
+
+ public bool Inverted
+ {
+ get => _inverted;
+ set
+ {
+ _inverted = value;
+ OnPropertyChanged();
+ }
+ }
+
+ protected override void OnSetConfiguration(LinearTransformationAdapter.Config configuration)
+ {
+ Inverted = configuration.Inverted;
+
+ }
+
+ protected override LinearTransformationAdapter.Config OnGetConfiguration()
+ {
+ return new LinearTransformationAdapter.Config
+ {
+ Inverted = Inverted
+ };
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/MidiAttachedNodeModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/MidiAttachedNodeModel.cs
new file mode 100644
index 0000000..f8ced20
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/MidiAttachedNodeModel.cs
@@ -0,0 +1,59 @@
+using OctoPatch.Plugin.Midi;
+
+namespace OctoPatch.DesktopClient.Models
+{
+ ///
+ /// Configuration model for all kind of attached nodes of the MIDI Device
+ ///
+ public sealed class MidiAttachedNodeModel : NodeConfigurationModel
+ {
+ private int _channel;
+
+ ///
+ /// Gets or sets the channel of the message filter
+ ///
+ public int Channel
+ {
+ get => _channel;
+ set
+ {
+ _channel = value;
+ OnPropertyChanged();
+ }
+ }
+
+ private int _key;
+
+ ///
+ /// Gets or sets the key of the message filter
+ ///
+ public int Key
+ {
+ get => _key;
+ set
+ {
+ _key = value;
+ OnPropertyChanged();
+ }
+ }
+
+ protected override void OnSetup(EmptyEnvironment environment)
+ {
+ }
+
+ protected override void OnSetConfiguration(AttachedNodeConfiguration configuration)
+ {
+ Channel = configuration?.Channel ?? 0;
+ Key = configuration?.Key ?? 0;
+ }
+
+ protected override AttachedNodeConfiguration OnGetConfiguration()
+ {
+ return new AttachedNodeConfiguration
+ {
+ Channel = Channel,
+ Key = Key
+ };
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/NodeConfigurationModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/NodeConfigurationModel.cs
index 8f239e2..e99efef 100644
--- a/src/Applications/OctoPatch.DesktopClient/Models/NodeConfigurationModel.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Models/NodeConfigurationModel.cs
@@ -2,16 +2,12 @@
namespace OctoPatch.DesktopClient.Models
{
- public abstract class NodeConfigurationModel : Model
- {
- public abstract void Setup(string environment);
-
- public abstract void SetConfiguration(string configuration);
-
- public abstract string GetConfiguration();
- }
-
- public abstract class NodeConfigurationModel : NodeConfigurationModel
+ ///
+ /// Basic configuration type for node configuration
+ ///
+ /// model type for configuration
+ /// model type for environment
+ public abstract class NodeConfigurationModel : ConfigurationModel
where TConfiguration : IConfiguration
where TEnvironment : IEnvironment
{
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/NodeModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/NodeModel.cs
index bd80124..6afbc29 100644
--- a/src/Applications/OctoPatch.DesktopClient/Models/NodeModel.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Models/NodeModel.cs
@@ -59,5 +59,14 @@ protected NodeModel(ConnectorDescription description) : this(description.Key)
{
Name = description.DisplayName;
}
+
+ protected NodeModel(Guid wireId)
+ {
+ this.Name = "Wire";
+ Items = new ObservableCollection();
+ Key = wireId.ToString();
+ State = NodeState.Uninitialized;
+
+ }
}
}
diff --git a/src/Applications/OctoPatch.DesktopClient/Models/WireNodeModel.cs b/src/Applications/OctoPatch.DesktopClient/Models/WireNodeModel.cs
new file mode 100644
index 0000000..56bb5cb
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Models/WireNodeModel.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace OctoPatch.DesktopClient.Models
+{
+ public sealed class WireNodeModel : NodeModel
+ {
+ public WireNodeModel(Guid wireId, string name) : base(wireId)
+ {
+ Name = name;
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/ModelsX/NodeModel.cs b/src/Applications/OctoPatch.DesktopClient/ModelsX/NodeModel.cs
new file mode 100644
index 0000000..69ee9b4
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/ModelsX/NodeModel.cs
@@ -0,0 +1,12 @@
+using OctoPatch.Descriptions;
+using OctoPatch.Setup;
+
+namespace OctoPatch.DesktopClient.ModelsX
+{
+ public sealed class NodeModel
+ {
+ public NodeSetup Setup { get; set; }
+
+ public NodeDescription Description { get; set; }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/NodeTemplateSelector.cs b/src/Applications/OctoPatch.DesktopClient/NodeTemplateSelector.cs
deleted file mode 100644
index 9620db3..0000000
--- a/src/Applications/OctoPatch.DesktopClient/NodeTemplateSelector.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-using OctoPatch.DesktopClient.Models;
-
-namespace OctoPatch.DesktopClient
-{
- public sealed class NodeTemplateSelector : DataTemplateSelector
- {
- public DataTemplate MidiDeviceTemplate { get; set; }
-
- public DataTemplate RestGetTemplate { get; set; }
-
- public override DataTemplate SelectTemplate(object item, DependencyObject container)
- {
- if (item is MidiDeviceModel)
- {
- return MidiDeviceTemplate;
- }
- else if(item is RestGetModel)
- {
- return RestGetTemplate;
- }
-
- return base.SelectTemplate(item, container);
- }
- }
-}
diff --git a/src/Applications/OctoPatch.DesktopClient/TreeTemplateSelector.cs b/src/Applications/OctoPatch.DesktopClient/TreeTemplateSelector.cs
index ca004d4..d732ede 100644
--- a/src/Applications/OctoPatch.DesktopClient/TreeTemplateSelector.cs
+++ b/src/Applications/OctoPatch.DesktopClient/TreeTemplateSelector.cs
@@ -18,6 +18,8 @@ public sealed class TreeTemplateSelector : DataTemplateSelector
public DataTemplate InputTemplate { get; set; }
+ public DataTemplate WireTemplate { get; set; }
+
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
switch (item)
@@ -34,6 +36,8 @@ public override DataTemplate SelectTemplate(object item, DependencyObject contai
return OutputTemplate;
case InputNodeModel _:
return InputTemplate;
+ case WireNodeModel _:
+ return WireTemplate;
}
return base.SelectTemplate(item, container);
diff --git a/src/Applications/OctoPatch.DesktopClient/ViewModels/IRuntimeViewModel.cs b/src/Applications/OctoPatch.DesktopClient/ViewModels/IRuntimeViewModel.cs
index 3f7439b..86aa50b 100644
--- a/src/Applications/OctoPatch.DesktopClient/ViewModels/IRuntimeViewModel.cs
+++ b/src/Applications/OctoPatch.DesktopClient/ViewModels/IRuntimeViewModel.cs
@@ -3,46 +3,187 @@
using System.Windows.Input;
using OctoPatch.Descriptions;
using OctoPatch.DesktopClient.Models;
-using OctoPatch.Setup;
+using OctoPatch.Server;
namespace OctoPatch.DesktopClient.ViewModels
{
public interface IRuntimeViewModel : INotifyPropertyChanged
{
+ IRuntime Runtime { get; }
+
+ #region Application
+
+ ///
+ /// Command to clean grid
+ ///
+ ICommand NewCommand { get; }
+
+ ///
+ /// Loads a file to the grid
+ ///
+ ICommand LoadCommand { get; }
+
+ ///
+ /// Saves the current grid to a file
+ ///
+ ICommand SaveCommand { get; }
+
+ #endregion
+
+ #region Toolbox
+
+ ///
+ /// List of available nodes to drag into tree
+ ///
ObservableCollection NodeDescriptions { get; }
+ ///
+ /// Gets or sets the current selected node description in toolbox
+ ///
NodeDescription SelectedNodeDescription { get; set; }
+ ///
+ /// Command to add the selected node description to the tree
+ ///
ICommand AddSelectedNodeDescription { get; }
+ #endregion
+
+ #region Patch
+
+ ///
+ /// Hierarchical tree structure
+ ///
+ ObservableCollection NodeTree { get; }
+
+ ///
+ /// Gets or sets the current selected node within the tree
+ ///
+ NodeModel SelectedNode { get; set; }
+
+ ///
+ /// Command to delete the current selected tree node
+ ///
+ ICommand RemoveSelectedNode { get; }
+
+ ///
+ /// Command to delete the current selected wire
+ ///
+ ICommand RemoveSelectedWire { get; }
+
+ #endregion
+
+ #region Context Toolbox
+
+ ///
+ /// List of available nodes for the current selected tree node
+ ///
ObservableCollection ContextNodeDescriptions { get; }
+ ///
+ /// Gets or sets the current selected node description of context toolbox
+ ///
NodeDescription SelectedContextNodeDescription { get; set; }
+ ///
+ /// Command to add the current selected context node description
+ /// to the current selected tree node
+ ///
ICommand AddSelectedContextNodeDescription { get; }
- ObservableCollection NodeTree { get; }
+ #endregion
- ICommand RemoveSelectedNode { get; }
+ #region Property bar
+
+ #region Node lifecycle management
+ ///
+ /// Command to start the current selected node
+ ///
ICommand StartSelectedNode { get; }
+ ///
+ /// Command to stop the current selected node
+ ///
ICommand StopSelectedNode { get; }
- NodeModel SelectedNode { get; set; }
+ #endregion
+ #region Common node configuration
+
+ ///
+ /// Gets the common configuration (name and description) of the current selected tree node
+ ///
NodeDescriptionModel NodeDescription { get; }
+ ///
+ /// Command to store all the changed made in the NodeDescription property
+ ///
ICommand SaveNodeDescription { get; }
- NodeConfigurationModel NodeConfiguration { get; }
+ #endregion
+
+ #region Node specific configuration
+ ///
+ /// Holds the specific configuration model for the current selected tree node
+ ///
+ ConfigurationModel NodeConfiguration { get; }
+
+ ///
+ /// Command to store all the changes made in the node configuration
+ ///
ICommand SaveNodeConfiguration { get; }
+ #endregion
+
+ #region Wire wizard
+
+ ///
+ /// gets the current selected ouptut connector (if available)
+ ///
OutputNodeModel SelectedWireConnector { get; }
+ ///
+ /// Command to take the selected output / input connector to wire them up
+ ///
ICommand TakeConnector { get; }
- ObservableCollection Wires { get; }
+ #endregion
+
+ #region Wire configuration
+
+ ///
+ /// List of all available adapters for the selected wire context
+ ///
+ ObservableCollection AdapterDescriptions { get; }
+
+ ///
+ /// Gets or sets the current selected adapter
+ ///
+ AdapterDescription SelectedAdapterDescription { get; set; }
+
+ ///
+ /// Command to apply current adapter selection to the selected wire
+ ///
+ ICommand SaveAdapter { get; }
+
+ #endregion
+
+ #region Adapter configuration
+
+ ///
+ /// Gets the configuration for the adapter of the current selected wire
+ ///
+ ConfigurationModel AdapterConfiguration { get; }
+
+ ///
+ /// Command to store all the changes in the adapter configuration
+ ///
+ ICommand SaveAdapterConfiguration { get; }
+
+ #endregion
+
+ #endregion
}
}
diff --git a/src/Applications/OctoPatch.DesktopClient/ViewModels/RuntimeViewModel.cs b/src/Applications/OctoPatch.DesktopClient/ViewModels/RuntimeViewModel.cs
index ec63c74..6d3af4e 100644
--- a/src/Applications/OctoPatch.DesktopClient/ViewModels/RuntimeViewModel.cs
+++ b/src/Applications/OctoPatch.DesktopClient/ViewModels/RuntimeViewModel.cs
@@ -2,14 +2,16 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
+using Microsoft.Win32;
+using Newtonsoft.Json;
using OctoPatch.Descriptions;
using OctoPatch.DesktopClient.Models;
-using OctoPatch.Plugin.Rest;
using OctoPatch.Server;
using OctoPatch.Setup;
@@ -19,14 +21,43 @@ public sealed class RuntimeViewModel : IRuntimeViewModel
{
private readonly IRuntime _runtime;
- private List _nodes;
+ private readonly List _nodes;
- private List _descriptions;
+ private readonly List _wires;
+ private readonly List _nodeDescriptions;
+
+ private readonly List _adapterDescriptions;
+
+ public IRuntime Runtime => _runtime;
+
+ #region Application
+
+ private readonly ActionCommand _newCommand;
+
+ ///
+ public ICommand NewCommand => _newCommand;
+
+ private readonly ActionCommand _loadCommand;
+
+ ///
+ public ICommand LoadCommand => _loadCommand;
+
+ private readonly ActionCommand _saveCommand;
+
+ ///
+ public ICommand SaveCommand => _saveCommand;
+
+ #endregion
+
+ #region Toolbox
+
+ ///
public ObservableCollection NodeDescriptions { get; }
private NodeDescription _selectedNodeDescription;
+ ///
public NodeDescription SelectedNodeDescription
{
get => _selectedNodeDescription;
@@ -41,43 +72,15 @@ public NodeDescription SelectedNodeDescription
private readonly ActionCommand _addSelectedNodeDescription;
+ ///
public ICommand AddSelectedNodeDescription => _addSelectedNodeDescription;
- public ObservableCollection ContextNodeDescriptions { get; }
-
- private NodeDescription _selectedContextNodeDescription;
-
- public NodeDescription SelectedContextNodeDescription
- {
- get => _selectedContextNodeDescription;
- set
- {
- _selectedContextNodeDescription = value;
- OnPropertyChanged();
-
- _addSelectedContextNodeDescription.Enabled = value != null;
- }
- }
-
- private readonly ActionCommand _addSelectedContextNodeDescription;
-
- public ICommand AddSelectedContextNodeDescription => _addSelectedContextNodeDescription;
+ #endregion
+ #region Patch
public ObservableCollection NodeTree { get; }
- private readonly ActionCommand _removeSelectedNode;
-
- public ICommand RemoveSelectedNode => _removeSelectedNode;
-
- private readonly ActionCommand _startSelectedNode;
-
- public ICommand StartSelectedNode => _startSelectedNode;
-
- private readonly ActionCommand _stopSelectedNode;
-
- public ICommand StopSelectedNode => _stopSelectedNode;
-
private NodeModel _selectedNode;
public NodeModel SelectedNode
@@ -94,7 +97,7 @@ public NodeModel SelectedNode
{
case InputNodeModel input:
- foreach (var description in _descriptions.OfType().Where(d => d.TypeKey == input.TypeKey))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.TypeKey == input.TypeKey))
{
ContextNodeDescriptions.Add(description);
}
@@ -102,7 +105,7 @@ public NodeModel SelectedNode
break;
case OutputNodeModel output:
- foreach (var description in _descriptions.OfType().Where(d => d.TypeKey == output.TypeKey))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.TypeKey == output.TypeKey))
{
ContextNodeDescriptions.Add(description);
}
@@ -111,7 +114,7 @@ public NodeModel SelectedNode
case CommonNodeModel common:
- foreach (var description in _descriptions.OfType().Where(d => d.ParentKey == common.Key))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.ParentKey == common.Key))
{
ContextNodeDescriptions.Add(description);
}
@@ -119,7 +122,7 @@ public NodeModel SelectedNode
break;
case AttachedNodeModel attached:
- foreach (var description in _descriptions.OfType().Where(d => d.ParentKey == attached.Key))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.ParentKey == attached.Key))
{
ContextNodeDescriptions.Add(description);
}
@@ -128,7 +131,7 @@ public NodeModel SelectedNode
case SplitterNodeModel splitter:
- foreach (var description in _descriptions.OfType().Where(d => d.ParentKey == splitter.Key))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.ParentKey == splitter.Key))
{
ContextNodeDescriptions.Add(description);
}
@@ -137,20 +140,21 @@ public NodeModel SelectedNode
case CollectorNodeModel collector:
- foreach (var description in _descriptions.OfType().Where(d => d.ParentKey == collector.Key))
+ foreach (var description in _nodeDescriptions.OfType().Where(d => d.ParentKey == collector.Key))
{
ContextNodeDescriptions.Add(description);
}
break;
-
}
- var item = _nodes.FirstOrDefault(n => n.Model == value);
+ #region node management
+ var item = _nodes.FirstOrDefault(n => n.Model == value);
if (item == null)
{
NodeDescription = null;
+ NodeConfiguration = null;
}
else
{
@@ -159,44 +163,111 @@ public NodeModel SelectedNode
Name = item.Setup.Name,
Description = item.Setup.Description
};
+
+ NodeConfiguration = ConfigurationMap.GetConfigurationModel(item.Setup.Key);
+ if (NodeConfiguration != null)
+ {
+ NodeConfiguration.Setup(item.Environment);
+ NodeConfiguration.SetConfiguration(item.Setup.Configuration);
+ }
}
_removeSelectedNode.Enabled = item != null;
_startSelectedNode.Enabled = item != null;
_stopSelectedNode.Enabled = item != null;
_saveNodeDescription.Enabled = item != null;
- _takeConnector.Enabled = (SelectedWireConnector != null && value is InputNodeModel) || value is OutputNodeModel;
+ _takeConnector.Enabled = SelectedWireConnector != null && value is InputNodeModel || value is OutputNodeModel;
+ _saveNodeConfiguration.Enabled = NodeConfiguration != null;
- //// TODO: Lookup model by Attribute
- if (item?.Setup.Key == "12ea0035-45af-4da8-8b5d-e1b9d9484ba4:MidiDeviceNode")
- {
- var model = new MidiDeviceModel();
- model.Setup(item.Environment);
- model.SetConfiguration(item.Setup.Configuration);
- NodeConfiguration = model;
- _saveNodeConfiguration.Enabled = true;
- }
- else if (item?.Setup.Key == "a6fe76d7-5f0e-4763-a3a5-fcaf43c71464:KeyboardNode")
- {
- NodeConfiguration = null;
- _saveNodeConfiguration.Enabled = true;
- }
- else if(item?.Setup.Key == $"{RestPlugin.PluginId[1..^1].ToLower()}:{nameof(RestGetNode)}")
+ #endregion
+
+ #region wire management
+
+ var wire = _wires.FirstOrDefault(w => w.InputWire == value || w.OutputWire == value);
+ if (wire == null)
{
- var model = new RestGetModel();
- model.Setup(item.Environment);
- model.SetConfiguration(item.Setup.Configuration);
- NodeConfiguration = model;
- _saveNodeConfiguration.Enabled = true;
+ AdapterDescriptions.Clear();
+ SelectedAdapterDescription = null;
+ AdapterConfiguration = null;
}
else
{
- NodeConfiguration = null;
- _saveNodeConfiguration.Enabled = false;
+ // Fill list of supported adapter
+ foreach (var adapter in wire.SupportedAdapter)
+ {
+ AdapterDescriptions.Add(adapter);
+ }
+
+ SelectedAdapterDescription =
+ AdapterDescriptions.FirstOrDefault(d => d.Key == wire.Setup.AdapterKey);
+
+ AdapterConfiguration = ConfigurationMap.GetConfigurationModel(wire.Setup.AdapterKey);
+ if (AdapterConfiguration != null)
+ {
+ AdapterConfiguration.Setup(wire.Environment);
+ AdapterConfiguration.SetConfiguration(wire.Setup.AdapterConfiguration);
+ }
+
}
+
+ _removeSelectedWire.Enabled = wire != null;
+ _saveAdapter.Enabled = wire != null;
+ _saveAdapterConfiguration.Enabled = AdapterConfiguration != null;
+
+ #endregion
}
}
+ private readonly ActionCommand _removeSelectedNode;
+
+ public ICommand RemoveSelectedNode => _removeSelectedNode;
+
+ private readonly ActionCommand _removeSelectedWire;
+
+ public ICommand RemoveSelectedWire => _removeSelectedWire;
+
+ #endregion
+
+ #region Context Toolbox
+
+ public ObservableCollection ContextNodeDescriptions { get; }
+
+ private NodeDescription _selectedContextNodeDescription;
+
+ public NodeDescription SelectedContextNodeDescription
+ {
+ get => _selectedContextNodeDescription;
+ set
+ {
+ _selectedContextNodeDescription = value;
+ OnPropertyChanged();
+
+ _addSelectedContextNodeDescription.Enabled = value != null;
+ }
+ }
+
+ private readonly ActionCommand _addSelectedContextNodeDescription;
+
+ public ICommand AddSelectedContextNodeDescription => _addSelectedContextNodeDescription;
+
+ #endregion
+
+ #region Property bar
+
+ #region Node lifecycle management
+
+ private readonly ActionCommand _startSelectedNode;
+
+ public ICommand StartSelectedNode => _startSelectedNode;
+
+ private readonly ActionCommand _stopSelectedNode;
+
+ public ICommand StopSelectedNode => _stopSelectedNode;
+
+ #endregion
+
+ #region Common node configuration
+
private NodeDescriptionModel _nodeDescription;
public NodeDescriptionModel NodeDescription
@@ -213,9 +284,13 @@ private set
public ICommand SaveNodeDescription => _saveNodeDescription;
- private NodeConfigurationModel _nodeConfiguration;
+ #endregion
+
+ #region Node specific configuration
+
+ private ConfigurationModel _nodeConfiguration;
- public NodeConfigurationModel NodeConfiguration
+ public ConfigurationModel NodeConfiguration
{
get => _nodeConfiguration;
private set
@@ -229,6 +304,10 @@ private set
public ICommand SaveNodeConfiguration => _saveNodeConfiguration;
+ #endregion
+
+ #region Wire wizard
+
private OutputNodeModel _selectedWireConnector;
public OutputNodeModel SelectedWireConnector
@@ -245,26 +324,79 @@ private set
public ICommand TakeConnector => _takeConnector;
- public ObservableCollection Wires { get; }
+ #endregion
+
+ #region Wire configuration
+
+ public ObservableCollection AdapterDescriptions { get; }
+
+ private AdapterDescription _selectedAdapterDescription;
+
+ public AdapterDescription SelectedAdapterDescription
+ {
+ get => _selectedAdapterDescription;
+ set
+ {
+ _selectedAdapterDescription = value;
+ OnPropertyChanged();
+ }
+ }
+
+ private readonly ActionCommand _saveAdapter;
+
+ public ICommand SaveAdapter => _saveAdapter;
+
+ #endregion
+
+ #region Adapter configuration
+
+ private ConfigurationModel _adapterConfiguration;
+
+ public ConfigurationModel AdapterConfiguration
+ {
+ get => _adapterConfiguration;
+ private set
+ {
+ _adapterConfiguration = value;
+ OnPropertyChanged();
+ }
+ }
+
+ private readonly ActionCommand _saveAdapterConfiguration;
+
+ public ICommand SaveAdapterConfiguration => _saveAdapterConfiguration;
+
+ #endregion
+
+ #endregion
public RuntimeViewModel()
{
_nodes = new List();
- _descriptions = new List();
+ _wires = new List();
+ _nodeDescriptions = new List();
+ _adapterDescriptions = new List();
NodeDescriptions = new ObservableCollection();
ContextNodeDescriptions = new ObservableCollection();
NodeTree = new ObservableCollection();
- Wires = new ObservableCollection();
+ AdapterDescriptions = new ObservableCollection();
_addSelectedNodeDescription = new ActionCommand(AddNodeDescriptionCallback, false);
_addSelectedContextNodeDescription = new ActionCommand(AddContextNodeDescriptionCallback, false);
_removeSelectedNode = new ActionCommand(RemoveSelectedNodeCallback, false);
+ _removeSelectedWire = new ActionCommand(RemoveSelectedWireCallback, false);
_startSelectedNode = new ActionCommand(StartSelectedNodeCallback, false);
_stopSelectedNode = new ActionCommand(StopSelectedNodeCallback, false);
_saveNodeDescription = new ActionCommand(SaveNodeDescriptionCallback, false);
_saveNodeConfiguration = new ActionCommand(SaveNodeConfigurationCallback, false);
_takeConnector = new ActionCommand(TakeConnectorCallback, false);
+ _saveAdapter = new ActionCommand(SaveAdapterCallback, false);
+ _saveAdapterConfiguration = new ActionCommand(SaveAdapterConfigurationCallback, false);
+
+ _newCommand = new ActionCommand(NewCommandCallback);
+ _loadCommand = new ActionCommand(LoadCommandCallback);
+ _saveCommand = new ActionCommand(SaveCommandCallback);
var repository = new Repository();
_runtime = new Runtime(repository);
@@ -276,10 +408,103 @@ public RuntimeViewModel()
_runtime.NodeEnvironmentChanged += RuntimeOnOnNodeEnvironmentChanged;
_runtime.WireAdded += RuntimeOnOnWireAdded;
_runtime.WireRemoved += RuntimeOnOnWireRemoved;
+ _runtime.WireUpdated += RuntimeOnWireUpdated;
+ _runtime.AdapterEnvironmentChanged += RuntimeOnAdapterEnvironmentChanged;
Task.Run(() => Setup(CancellationToken.None));
}
+ private async void SaveCommandCallback(object obj)
+ {
+ var dialog = new SaveFileDialog
+ {
+ Filter = "OctoPatch Grid|*.grid"
+ };
+
+ if (dialog.ShowDialog() == true)
+ {
+ var grid = await _runtime.GetConfiguration(CancellationToken.None);
+ var output = JsonConvert.SerializeObject(grid);
+ await File.WriteAllTextAsync(dialog.FileName, output);
+ }
+ }
+
+ private async void LoadCommandCallback(object obj)
+ {
+ var dialog = new OpenFileDialog
+ {
+ Filter = "OctoPatch Grid|*.grid"
+ };
+
+ if (dialog.ShowDialog() == true)
+ {
+ var input = await File.ReadAllTextAsync(dialog.FileName, CancellationToken.None);
+ var grid = JsonConvert.DeserializeObject(input);
+ await _runtime.SetConfiguration(grid, CancellationToken.None);
+ }
+ }
+
+ private async void NewCommandCallback(object obj)
+ {
+ await _runtime.SetConfiguration(null, CancellationToken.None);
+ }
+
+ private void RuntimeOnWireUpdated(WireSetup wireSetup)
+ {
+ var wire = _wires.FirstOrDefault(n => n.Setup.WireId == wireSetup.WireId);
+ if (wire == null)
+ {
+ return;
+ }
+
+ wire.Setup = wireSetup;
+ }
+
+ private void RuntimeOnAdapterEnvironmentChanged(Guid wireId, string environment)
+ {
+ var wire = _wires.FirstOrDefault(n => n.Setup.WireId == wireId);
+ if (wire == null)
+ {
+ return;
+ }
+
+ wire.Environment = environment;
+ }
+
+
+ private void SaveAdapterConfigurationCallback(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ private async void SaveAdapterCallback(object obj)
+ {
+ var node = SelectedNode;
+ var item = _wires.FirstOrDefault(n => n.InputWire == node || n.OutputWire == node);
+ if (item == null)
+ {
+ return;
+ }
+
+ var adapterDescription = SelectedAdapterDescription;
+ if (adapterDescription != null)
+ {
+ await _runtime.SetAdapter(item.Setup.WireId, adapterDescription.Key, CancellationToken.None);
+ }
+ }
+
+ private async void RemoveSelectedWireCallback(object obj)
+ {
+ var node = SelectedNode;
+ var item = _wires.FirstOrDefault(n => n.InputWire == node || n.OutputWire == node);
+ if (item == null)
+ {
+ return;
+ }
+
+ await _runtime.RemoveWire(item.Setup.WireId, CancellationToken.None);
+ }
+
private async void TakeConnectorCallback(object obj)
{
var node = SelectedNode;
@@ -295,8 +520,9 @@ private async void TakeConnectorCallback(object obj)
if (SelectedWireConnector != null && node is InputNodeModel inputNode)
{
await _runtime.AddWire(
- SelectedWireConnector.ParentId, SelectedWireConnector.Key,
- inputNode.ParentId, inputNode.Key, CancellationToken.None);
+ inputNode.ParentId, inputNode.Key,
+ SelectedWireConnector.ParentId, SelectedWireConnector.Key,
+ CancellationToken.None);
SelectedWireConnector = null;
_takeConnector.Enabled = false;
}
@@ -352,15 +578,15 @@ private async void AddContextNodeDescriptionCallback(object obj)
if (contextNode is SplitterNodeDescription)
{
- await _runtime.AddNode(contextNode.Key, parentId, connectorKey, CancellationToken.None);
+ await _runtime.AddNode(contextNode.Key, parentId, connectorKey, 0, 0, CancellationToken.None);
}
else if (contextNode is CollectorNodeDescription)
{
- await _runtime.AddNode(contextNode.Key, parentId, connectorKey, CancellationToken.None);
+ await _runtime.AddNode(contextNode.Key, parentId, connectorKey, 0, 0, CancellationToken.None);
}
else if (contextNode is AttachedNodeDescription)
{
- await _runtime.AddNode(contextNode.Key, parentId, null, CancellationToken.None);
+ await _runtime.AddNode(contextNode.Key, parentId, null, 0, 0, CancellationToken.None);
}
}
@@ -406,6 +632,7 @@ private void RuntimeOnOnNodeUpdated(NodeSetup setup)
}
node.Setup = setup;
+ node.Model.Name = setup.Name;
}
private void RuntimeOnOnNodeStateChanged(Guid nodeId, NodeState state)
@@ -471,16 +698,52 @@ private async void AddNodeDescriptionCallback(object obj)
var description = SelectedNodeDescription;
if (description != null)
{
- await _runtime.AddNode(description.Key, null, null, CancellationToken.None);
+ await _runtime.AddNode(description.Key, null, null, 0, 0, CancellationToken.None);
}
}
- private void RuntimeOnOnWireRemoved(Guid obj)
+ private void RuntimeOnOnWireRemoved(Guid wireId)
{
+ var wire = _wires.FirstOrDefault(n => n.Setup.WireId == wireId);
+ if (wire == null)
+ {
+ return;
+ }
+
+ // Remove node in tree
+ RemoveRecursive(wire.InputWire, NodeTree);
+ RemoveRecursive(wire.OutputWire, NodeTree);
+
+ _wires.Remove(wire);
}
- private void RuntimeOnOnWireAdded(WireSetup obj)
+ private async void RuntimeOnOnWireAdded(WireSetup wire)
{
+ var inputNode = _nodes.First(n => n.Setup.NodeId == wire.InputNodeId);
+ var inputConnector = inputNode.Model.Items.OfType()
+ .First(m => m.Key == wire.InputConnectorKey);
+
+ var outputNode = _nodes.First(n => n.Setup.NodeId == wire.OutputNodeId);
+ var outputConnector = outputNode.Model.Items.OfType()
+ .First(m => m.Key == wire.OutputConnectorKey);
+
+ var inputWire = new WireNodeModel(wire.WireId, $"Wire to {outputNode.Model.Name} ({outputConnector.Name})");
+ inputConnector.Items.Add(inputWire);
+
+ var outputWire = new WireNodeModel(wire.WireId, $"Wire to {inputNode.Model.Name} ({inputConnector.Name})");
+ outputConnector.Items.Add(outputWire);
+
+ var supportedAdapters = await _runtime.GetSupportedAdapters(wire.WireId, CancellationToken.None);
+
+ _wires.Add(new WireItem
+ {
+ InputConnector = inputConnector,
+ InputWire = inputWire,
+ OutputConnector = outputConnector,
+ OutputWire = outputWire,
+ Setup = wire,
+ SupportedAdapter = _adapterDescriptions.Where(a => supportedAdapters.Contains(a.Key)).ToArray()
+ });
}
private void RuntimeOnOnNodeRemoved(Guid obj)
@@ -520,7 +783,7 @@ private void RemoveRecursive(NodeModel model, ObservableCollection li
private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string environment)
{
// identify description
- var description = _descriptions.FirstOrDefault(d => d.Key == setup.Key);
+ var description = _nodeDescriptions.FirstOrDefault(d => d.Key == setup.Key);
NodeModel nodeModel = null;
switch (description)
@@ -534,7 +797,7 @@ private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string envir
return;
}
- attachedParent.Model.Items.Add(new AttachedNodeModel(setup.NodeId, attached));
+ attachedParent.Model.Items.Add(nodeModel);
break;
case CollectorNodeDescription collector:
nodeModel = new CollectorNodeModel(setup.NodeId, collector);
@@ -552,7 +815,7 @@ private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string envir
return;
}
- input.Items.Add(new CollectorNodeModel(setup.NodeId, collector));
+ input.Items.Add(nodeModel);
break;
case SplitterNodeDescription splitter:
nodeModel = new SplitterNodeModel(setup.NodeId, splitter);
@@ -570,7 +833,7 @@ private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string envir
return;
}
- output.Items.Add(new SplitterNodeModel(setup.NodeId, splitter));
+ output.Items.Add(nodeModel);
break;
case CommonNodeDescription common:
@@ -591,15 +854,19 @@ private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string envir
public async Task Setup(CancellationToken cancellationToken)
{
- var descriptions = await _runtime.GetNodeDescriptions(cancellationToken);
+ var nodeDescriptions = await _runtime.GetNodeDescriptions(cancellationToken);
+ var adapterDescriptions = await _runtime.GetAdapterDescriptions(cancellationToken);
- _descriptions.Clear();
- _descriptions.AddRange(descriptions);
+ _nodeDescriptions.Clear();
+ _nodeDescriptions.AddRange(nodeDescriptions);
- foreach (var description in _descriptions.OfType())
+ foreach (var description in _nodeDescriptions.OfType())
{
NodeDescriptions.Add(description);
}
+
+ _adapterDescriptions.Clear();
+ _adapterDescriptions.AddRange(adapterDescriptions);
}
public event PropertyChangedEventHandler PropertyChanged;
@@ -617,5 +884,22 @@ private sealed class NodeItem
public NodeModel Model { get; set; }
}
+
+ private sealed class WireItem
+ {
+ public OutputNodeModel InputConnector { get; set; }
+
+ public InputNodeModel OutputConnector { get; set; }
+
+ public WireNodeModel InputWire { get; set; }
+
+ public WireNodeModel OutputWire { get; set; }
+
+ public WireSetup Setup { get; set; }
+
+ public string Environment { get; set; }
+
+ public AdapterDescription[] SupportedAdapter { get; set; }
+ }
}
}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml
deleted file mode 100644
index b6dcc42..0000000
--- a/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml.cs
deleted file mode 100644
index e782e4e..0000000
--- a/src/Applications/OctoPatch.DesktopClient/Views/CommonNodeSetupView.xaml.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Windows.Controls;
-
-namespace OctoPatch.DesktopClient.Views
-{
- ///
- /// Interaction logic for NodeInstanceView.xaml
- ///
- public partial class CommonNodeSetupView : UserControl
- {
- public CommonNodeSetupView()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml
new file mode 100644
index 0000000..ce33d51
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml.cs
new file mode 100644
index 0000000..713489b
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/ConnectorView.xaml.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+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 OctoPatch.ContentTypes;
+
+namespace OctoPatch.DesktopClient.Views
+{
+ ///
+ /// Interaction logic for ConnectorView.xaml
+ ///
+ public partial class ConnectorView : UserControl
+ {
+ // Using a DependencyProperty as the backing store for ContentType. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty ContentTypeProperty =
+ DependencyProperty.Register("ContentType", typeof(ContentType), typeof(ConnectorView));
+
+ [Bindable(true)]
+ public ContentType ContentType
+ {
+ get => (ContentType)GetValue(ContentTypeProperty);
+ set => SetValue(ContentTypeProperty, value);
+ }
+
+ public ConnectorView()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnMouseEnter(MouseEventArgs e)
+ {
+ if (ContentType is ComplexContentType complexContentType)
+ {
+ var x = complexContentType.Type;
+ }
+
+ base.OnMouseEnter(e);
+ }
+
+ protected override void OnMouseLeave(MouseEventArgs e)
+ {
+ base.OnMouseLeave(e);
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml
new file mode 100644
index 0000000..41b3390
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml.cs
new file mode 100644
index 0000000..aacdd91
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/KeyboardStringView.xaml.cs
@@ -0,0 +1,17 @@
+using System.Windows.Controls;
+using OctoPatch.DesktopClient.Models;
+
+namespace OctoPatch.DesktopClient.Views
+{
+ ///
+ /// Interaction logic for KeyboardStringView.xaml
+ ///
+ [ConfigurationMap("a6fe76d7-5f0e-4763-a3a5-fcaf43c71464:KeyboardStringNode", typeof(KeyboardStringModel))]
+ public partial class KeyboardStringView : UserControl
+ {
+ public KeyboardStringView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml
new file mode 100644
index 0000000..37e3202
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml.cs
new file mode 100644
index 0000000..f252cb2
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/LinearAdapterView.xaml.cs
@@ -0,0 +1,17 @@
+using System.Windows.Controls;
+using OctoPatch.DesktopClient.Models;
+
+namespace OctoPatch.DesktopClient.Views
+{
+ ///
+ /// Interaction logic for LinearAdapterView.xaml
+ ///
+ [ConfigurationMap("598D58EB-756D-4BF7-B04B-AC9603315B6D:LinearTransformationAdapter", typeof(LinearAdapterModel))]
+ public partial class LinearAdapterView : UserControl
+ {
+ public LinearAdapterView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml
similarity index 52%
rename from src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml
rename to src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml
index 8c995f5..46eeadc 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml
+++ b/src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml
@@ -1,10 +1,10 @@
-
@@ -12,14 +12,15 @@
-
-
-
+
+
+
-
-
+
+
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml.cs
new file mode 100644
index 0000000..32ba9d4
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/MidiAttachedView.xaml.cs
@@ -0,0 +1,21 @@
+using System.Windows.Controls;
+using OctoPatch.DesktopClient.Models;
+using OctoPatch.Plugin.Midi;
+
+namespace OctoPatch.DesktopClient.Views
+{
+ ///
+ /// Interaction logic for MidiAttachedView.xaml
+ ///
+ [ConfigurationMap("12ea0035-45af-4da8-8b5d-e1b9d9484ba4:ControlMidiOutputNode", typeof(MidiAttachedNodeModel))]
+ [ConfigurationMap("12ea0035-45af-4da8-8b5d-e1b9d9484ba4:ControlMidiInputNode", typeof(MidiAttachedNodeModel))]
+ [ConfigurationMap("12ea0035-45af-4da8-8b5d-e1b9d9484ba4:NoteMidiOutputNode", typeof(MidiAttachedNodeModel))]
+ [ConfigurationMap("12ea0035-45af-4da8-8b5d-e1b9d9484ba4:NoteMidiInputNode", typeof(MidiAttachedNodeModel))]
+ public partial class MidiAttachedView : UserControl
+ {
+ public MidiAttachedView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/MidiDeviceView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/MidiDeviceView.xaml.cs
index b2beef6..3e96342 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/MidiDeviceView.xaml.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Views/MidiDeviceView.xaml.cs
@@ -1,21 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-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 System.Windows.Controls;
+using OctoPatch.DesktopClient.Models;
namespace OctoPatch.DesktopClient.Views
{
///
/// Interaction logic for MidiDeviceView.xaml
///
+ [ConfigurationMap("12ea0035-45af-4da8-8b5d-e1b9d9484ba4:MidiDeviceNode", typeof(MidiDeviceModel))]
public partial class MidiDeviceView : UserControl
{
public MidiDeviceView()
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml.cs
deleted file mode 100644
index ed0f9de..0000000
--- a/src/Applications/OctoPatch.DesktopClient/Views/NodeDescriptionView.xaml.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-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;
-
-namespace OctoPatch.DesktopClient.Views
-{
- ///
- /// Interaction logic for NodeDescriptionView.xaml
- ///
- public partial class NodeDescriptionView : UserControl
- {
- public NodeDescriptionView()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml
new file mode 100644
index 0000000..2529bac
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/ToolboxView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml.cs
similarity index 79%
rename from src/Applications/OctoPatch.DesktopClient/Views/ToolboxView.xaml.cs
rename to src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml.cs
index 6c77246..6a4ffd8 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/ToolboxView.xaml.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Views/NodeView.xaml.cs
@@ -14,11 +14,11 @@
namespace OctoPatch.DesktopClient.Views
{
///
- /// Interaction logic for ToolboxView.xaml
+ /// Interaction logic for NodeView.xaml
///
- public partial class ToolboxView : UserControl
+ public partial class NodeView : UserControl
{
- public ToolboxView()
+ public NodeView()
{
InitializeComponent();
}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml
new file mode 100644
index 0000000..838a735
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml
@@ -0,0 +1,9 @@
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml.cs
new file mode 100644
index 0000000..1eb5422
--- /dev/null
+++ b/src/Applications/OctoPatch.DesktopClient/Views/PatchView.xaml.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Concurrent;
+using System.Linq;
+using System.Threading;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using OctoPatch.Descriptions;
+using OctoPatch.Server;
+using OctoPatch.Setup;
+
+namespace OctoPatch.DesktopClient.Views
+{
+ ///
+ /// Interaction logic for PatchView.xaml
+ ///
+ public partial class PatchView : Canvas
+ {
+ private IRuntime _runtime;
+
+ private NodeDescription[] _nodeDescriptions;
+
+ private readonly ConcurrentDictionary _nodes;
+
+ private NodeModel _selectedNode;
+
+ private NodeModel _draggingNode;
+
+ private Point _draggingStart;
+
+ public PatchView()
+ {
+ InitializeComponent();
+
+ _nodes = new ConcurrentDictionary();
+
+ Loaded += OnLoaded;
+ MouseDown += OnMouseDown;
+ MouseUp += OnMouseUp;
+ MouseMove += OnMouseMove;
+ }
+
+ private void OnMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (e.ChangedButton != MouseButton.Left)
+ {
+ return;
+ }
+
+ var position = e.GetPosition(this);
+
+ var node = _nodes.Values.FirstOrDefault(n =>
+ GetLeft(n.View) <= position.X &&
+ GetLeft(n.View) + n.View.ActualWidth >= position.X &&
+ GetTop(n.View) <= position.Y &&
+ GetTop(n.View) + n.View.ActualHeight >= position.Y);
+
+ // Find node
+ //var widthHalf = (double) NodeWidth / 2;
+ //var heightHalf = (double) NodeHeight / 2;
+ //var node = _nodes.Values.FirstOrDefault(n =>
+ // n.View.ActualWidth / 2 Model.Setup.PositionX - widthHalf <= position.X &&
+ // n.Model.Setup.PositionX + widthHalf >= position.X &&
+ // n.Model.Setup.PositionY - heightHalf <= position.Y &&
+ // n.Model.Setup.PositionY + heightHalf >= position.Y);
+
+ //var node = _nodes.Values.FirstOrDefault(n =>
+ // n.Model.Setup.PositionX - widthHalf <= position.X &&
+ // n.Model.Setup.PositionX + widthHalf >= position.X &&
+ // n.Model.Setup.PositionY - heightHalf <= position.Y &&
+ // n.Model.Setup.PositionY + heightHalf >= position.Y);
+
+ SetSelectedNode(node);
+
+ _draggingNode = node;
+ _draggingStart = position;
+ }
+
+ private void SetSelectedNode(NodeModel nodeModel)
+ {
+ // Deselect current selection
+ if (_selectedNode != null)
+ {
+ _selectedNode.View.BorderBrush = null;
+ }
+
+ _selectedNode = null;
+
+ // Select new selection
+ if (nodeModel != null)
+ {
+ _selectedNode = nodeModel;
+ _selectedNode.View.BorderBrush = new SolidColorBrush(Colors.Black);
+ }
+ }
+
+ private void OnMouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if (e.ChangedButton != MouseButton.Left)
+ {
+ return;
+ }
+
+ // Handle drag/drop
+ if (_draggingNode != null)
+ {
+ var position = e.GetPosition(this);
+ var newPos = new Point(_draggingNode.Model.Setup.PositionX, _draggingNode.Model.Setup.PositionY) +
+ (position - _draggingStart);
+
+ SetLeft(_draggingNode.View, newPos.X - _draggingNode.View.ActualWidth / 2);
+ SetTop(_draggingNode.View, newPos.Y - _draggingNode.View.ActualHeight / 2);
+
+ _runtime.SetNodePosition(_draggingNode.Model.Setup.NodeId, (int) newPos.X, (int) newPos.Y,
+ CancellationToken.None);
+
+ _draggingNode = null;
+ }
+ }
+
+ private async void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ _runtime = DataContext as IRuntime;
+
+ _nodeDescriptions = (await _runtime.GetNodeDescriptions(CancellationToken.None)).ToArray();
+
+ _runtime.NodeAdded += RuntimeOnOnNodeAdded;
+ _runtime.NodeRemoved += RuntimeOnOnNodeRemoved;
+ _runtime.NodeUpdated += RuntimeOnOnNodeUpdated;
+ _runtime.NodeStateChanged += RuntimeOnOnNodeStateChanged;
+ _runtime.NodeEnvironmentChanged += RuntimeOnOnNodeEnvironmentChanged;
+ _runtime.WireAdded += RuntimeOnOnWireAdded;
+ _runtime.WireRemoved += RuntimeOnOnWireRemoved;
+ _runtime.WireUpdated += RuntimeOnWireUpdated;
+ _runtime.AdapterEnvironmentChanged += RuntimeOnAdapterEnvironmentChanged;
+ }
+
+ private void OnMouseMove(object sender, MouseEventArgs e)
+ {
+ if (_draggingNode == null)
+ {
+ return;
+ }
+
+ var position = e.GetPosition(this);
+ var newPos = new Point(_draggingNode.Model.Setup.PositionX, _draggingNode.Model.Setup.PositionY) + (position - _draggingStart);
+
+ SetLeft(_draggingNode.View, newPos.X - _draggingNode.View.ActualWidth / 2);
+ SetTop(_draggingNode.View, newPos.Y - _draggingNode.View.ActualHeight / 2);
+ }
+
+ #region Nodes
+
+ private void RuntimeOnOnNodeAdded(NodeSetup setup, NodeState state, string environment)
+ {
+ var description = _nodeDescriptions.First(d => d.Key == setup.Key);
+ var model = new ModelsX.NodeModel
+ {
+ Setup = setup,
+ Description = description,
+ };
+
+
+ var nodeView = new NodeView
+ {
+ DataContext = model,
+ Background = new SolidColorBrush(Colors.Brown),
+ BorderThickness = new Thickness(2)
+ };
+
+ SetLeft(nodeView, -(nodeView.ActualWidth / 2) + setup.PositionX);
+ SetTop(nodeView, -(nodeView.ActualHeight / 2) + setup.PositionY);
+ Children.Add(nodeView);
+
+ var node = new NodeModel
+ {
+ Model = model,
+ View = nodeView,
+ State = state,
+ Environment = environment
+ };
+
+ _nodes.TryAdd(setup.NodeId, node);
+ }
+
+ private void RuntimeOnOnNodeUpdated(NodeSetup setup)
+ {
+ if (!_nodes.TryGetValue(setup.NodeId, out var node))
+ {
+ return;
+ }
+
+ node.Model.Setup = setup;
+
+ // TODO: Update control
+
+ SetLeft(node.View, setup.PositionX - node.View.ActualWidth / 2);
+ SetTop(node.View, setup.PositionY - node.View.ActualHeight / 2);
+ }
+
+ private void RuntimeOnOnNodeEnvironmentChanged(Guid nodeId, string environment)
+ {
+ if (!_nodes.TryGetValue(nodeId, out var node))
+ {
+ return;
+ }
+
+ node.Environment = environment;
+ }
+
+ private void RuntimeOnOnNodeStateChanged(Guid nodeId, NodeState state)
+ {
+ if (!_nodes.TryGetValue(nodeId, out var node))
+ {
+ return;
+ }
+
+ node.State = state;
+
+ // TODO: Change
+ }
+
+ private void RuntimeOnOnNodeRemoved(Guid nodeId)
+ {
+ if (!_nodes.TryRemove(nodeId, out var node))
+ {
+ return;
+ }
+
+ // Remove control
+ Children.Remove(node.View);
+ }
+
+ private sealed class NodeModel
+ {
+ public ModelsX.NodeModel Model { get; set; }
+
+ public NodeView View { get; set; }
+
+ public NodeState State { get; set; }
+
+ public string Environment { get; set; }
+ }
+
+ #endregion
+
+ #region Wires
+
+ private void RuntimeOnOnWireAdded(WireSetup setup)
+ {
+ }
+
+ private void RuntimeOnWireUpdated(WireSetup setup)
+ {
+ }
+
+ private void RuntimeOnAdapterEnvironmentChanged(Guid wireId, string enviroment)
+ {
+ }
+
+ private void RuntimeOnOnWireRemoved(Guid wireId)
+ {
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/RestGetView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/RestGetView.xaml.cs
index 2590d36..e8b6106 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/RestGetView.xaml.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Views/RestGetView.xaml.cs
@@ -1,10 +1,12 @@
using System.Windows.Controls;
+using OctoPatch.DesktopClient.Models;
namespace OctoPatch.DesktopClient.Views
{
///
/// Interaction logic for RestGetView.xaml
///
+ [ConfigurationMap("40945D30-186D-4AEE-8895-058FB4759EFF:RestGetNode", typeof(RestGetModel))]
public partial class RestGetView : UserControl
{
public RestGetView()
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml b/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml
index f53743f..87ec3c0 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml
+++ b/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml
@@ -17,19 +17,6 @@
Uninitialized="Gray"
Failed="Red" />
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -87,24 +74,67 @@
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
@@ -112,10 +142,33 @@
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -124,34 +177,64 @@
-
+
+
+
-
+
+
-
+
+ Visibility="{Binding SelectedNode, Converter={StaticResource ConfigurableNodeToVisibilityConverter}}">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+ Visibility="{Binding SelectedNode, Converter={StaticResource ConfigurableNodeToVisibilityConverter}}">
@@ -164,7 +247,9 @@
Foreground="White"
FontWeight="Bold"
Padding="5" />
-
+
+
+
@@ -172,7 +257,7 @@
+ Visibility="{Binding Path=ContextNodeDescriptions.Count, Converter={StaticResource AttachableNodesToVisibilityConverter}}">
@@ -192,7 +277,7 @@
+ Visibility="{Binding SelectedNode, Converter={StaticResource AllNodeToVisibilityConverter}}">
@@ -210,8 +295,8 @@
-
-
+
+
@@ -235,6 +320,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml.cs b/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml.cs
index 69adbc0..b47c304 100644
--- a/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml.cs
+++ b/src/Applications/OctoPatch.DesktopClient/Views/RuntimeView.xaml.cs
@@ -1,4 +1,5 @@
-using System.Windows;
+using System.ComponentModel;
+using System.Windows;
using System.Windows.Controls;
using OctoPatch.DesktopClient.Models;
using OctoPatch.DesktopClient.ViewModels;
@@ -16,6 +17,22 @@ public RuntimeView()
{
InitializeComponent();
DataContext = _viewModel = new RuntimeViewModel();
+
+ _viewModel.PropertyChanged += ViewModelOnPropertyChanged;
+ }
+
+ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(RuntimeViewModel.NodeConfiguration))
+ {
+ // Create proper node configuration control
+ NodeConfigurationContainer.Content = ConfigurationMap.GetConfigurationView(_viewModel.NodeConfiguration);
+ }
+ else if (e.PropertyName == nameof(RuntimeViewModel.AdapterConfiguration))
+ {
+ // Create proper adapter configuration control
+ AdapterConfigurationContainer.Content = ConfigurationMap.GetConfigurationView(_viewModel.AdapterConfiguration);
+ }
}
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs