diff options
| author | Roy <roy.mail.net@gmail.com> | 2017-11-12 10:31:01 +0200 |
|---|---|---|
| committer | Roy <roy.mail.net@gmail.com> | 2017-11-12 10:31:01 +0200 |
| commit | 255c97282edaf2e0e17ce3ad253653c36dd56243 (patch) | |
| tree | e50a412fb877af2da5fa45c0a6a68710844f34f3 /Software | |
| parent | 5af3faff68fb32e0f7da874eb0c4652b8c282183 (diff) | |
| download | Tango-255c97282edaf2e0e17ce3ad253653c36dd56243.tar.gz Tango-255c97282edaf2e0e17ce3ad253653c36dd56243.zip | |
Fix previous commit ?
Diffstat (limited to 'Software')
69 files changed, 3444 insertions, 124 deletions
diff --git a/Software/PMR/Messages/Common/MessageType.proto b/Software/PMR/Messages/Common/MessageType.proto index 857e6874c..2f37c807b 100644 --- a/Software/PMR/Messages/Common/MessageType.proto +++ b/Software/PMR/Messages/Common/MessageType.proto @@ -8,6 +8,8 @@ enum MessageType RGB = 0; Job = 1; Segment = 2; - Stub1Request = 3; - Stub1Response = 4; + CalculateRequest = 3; + CalculateResponse = 4; + ProgressRequest = 5; + ProgressResponse = 6; } diff --git a/Software/PMR/Messages/Stubs/Calculate.proto b/Software/PMR/Messages/Stubs/Calculate.proto index e202613ff..197b327e7 100644 --- a/Software/PMR/Messages/Stubs/Calculate.proto +++ b/Software/PMR/Messages/Stubs/Calculate.proto @@ -3,13 +3,13 @@ syntax = "proto3"; package Tango.PMR.Stubs; option java_package = "com.twine.tango.pmr.stubs"; -message Stub1Request +message CalculateRequest { - int32 A = 1; - int32 B = 2; + double A = 1; + double B = 2; } -message Stub1Response +message CalculateResponse { - int32 Sum = 1; + double Sum = 1; }
\ No newline at end of file diff --git a/Software/PMR/Messages/Stubs/Progress.proto b/Software/PMR/Messages/Stubs/Progress.proto new file mode 100644 index 000000000..3a5222a30 --- /dev/null +++ b/Software/PMR/Messages/Stubs/Progress.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package Tango.PMR.Stubs; +option java_package = "com.twine.tango.pmr.stubs"; + +message ProgressRequest +{ + +} + +message ProgressResponse +{ + double Progress = 1; +}
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.Core/ExtensionMethods/DependencyObjectExtensions.cs b/Software/Visual Studio/Tango.Core/ExtensionMethods/DependencyObjectExtensions.cs new file mode 100644 index 000000000..16fd43728 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ExtensionMethods/DependencyObjectExtensions.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Media.Animation; +/// <exclude/> +/// <summary> +/// Contains a collection of DependencyObject extension methods. +/// </summary> +public static class DependencyObjectExtensions +{ + /// <summary> + /// Invokes the current dependency object dispatcher. + /// </summary> + /// <param name="dependencyObject">The dependency object.</param> + /// <param name="action">The action.</param> + public static void BeginInvoke(this DependencyObject dependencyObject, Action action) + { + dependencyObject.Dispatcher.BeginInvoke(action); + } + + /// <summary> + /// Invokes the specified action. + /// </summary> + /// <param name="dependencyObject">The dependency object.</param> + /// <param name="action">The action.</param> + public static void Invoke(this DependencyObject dependencyObject, Action action) + { + dependencyObject.Dispatcher.Invoke(action); + } + + /// <summary> + /// Determines whether this object is currently in design time mode. + /// </summary> + /// <param name="obj">The object.</param> + /// <returns></returns> + public static bool IsInDesignMode(this DependencyObject obj) + { + return (DesignerProperties.GetIsInDesignMode(obj)); + } + + + /// <summary> + /// Binds the specified dependency property to a another object property. + /// </summary> + /// <param name="target">The target dependency object.</param> + /// <param name="targetDP">The target dependency property.</param> + /// <param name="source">The source object.</param> + /// <param name="sourceDP">The source dependency property.</param> + /// <param name="mode">Binding mode.</param> + /// <param name="converter">Binding converter.</param> + /// <returns></returns> + public static Binding Bind(this DependencyObject target, DependencyProperty targetDP, DependencyObject source, DependencyProperty sourceDP, BindingMode mode, IValueConverter converter = null) + { + Binding binding = new Binding(); + binding.Mode = mode; + binding.Source = source; + binding.Path = new PropertyPath(sourceDP); + binding.Converter = converter; + BindingOperations.SetBinding(target, targetDP, binding); + return binding; + } + + /// <summary> + /// Binds the specified dependency property to a another object property. + /// </summary> + /// <param name="target">The target dependency object.</param> + /// <param name="targetDP">The target dependency property.</param> + /// <param name="source">The source object.</param> + /// <param name="sourceDP">The source dependency property.</param> + /// <param name="mode">Binding mode.</param> + /// <returns></returns> + public static Binding Bind(this DependencyObject target, DependencyProperty targetDP, DependencyObject source, DependencyProperty sourceDP, BindingMode mode = BindingMode.Default) + { + Binding binding = new Binding(); + binding.Mode = mode; + binding.Source = source; + binding.Path = new PropertyPath(sourceDP); + BindingOperations.SetBinding(target, targetDP, binding); + return binding; + } + + /// <summary> + /// Create asynchronous binding between target and source. + /// </summary> + /// <param name="target">The target dependency object.</param> + /// <param name="targetDP">The target dependency property.</param> + /// <param name="source">The source object.</param> + /// <param name="sourceDP">The source dependency property.</param> + /// <param name="mode">Binding mode.</param> + /// <returns></returns> + public static Binding BindAsync(this DependencyObject target, DependencyProperty targetDP, DependencyObject source, DependencyProperty sourceDP, BindingMode mode = BindingMode.Default) + { + Binding binding = new Binding(); + binding.Mode = mode; + binding.Source = source; + binding.Path = new PropertyPath(sourceDP); + binding.IsAsync = true; + binding.BindsDirectlyToSource = true; + BindingOperations.SetBinding(target, targetDP, binding); + return binding; + } + + /// <summary> + /// Binds the specified dependency property to a another object property. + /// </summary> + /// <param name="target">The target dependency object.</param> + /// <param name="targetDP">The target dependency property.</param> + /// <param name="source">The source object.</param> + /// <param name="sourceDP">The source dependency property name.</param> + /// <param name="mode">Binding mode.</param> + /// <returns></returns> + public static Binding Bind(this DependencyObject target, DependencyProperty targetDP, DependencyObject source, String sourceDP, BindingMode mode = BindingMode.Default) + { + Binding binding = new Binding(); + binding.Mode = mode; + binding.Source = source; + binding.Path = new PropertyPath(sourceDP); + BindingOperations.SetBinding(target, targetDP, binding); + return binding; + } + + /// <summary> + /// Clears bindings from the specified dependency property. + /// </summary> + /// <param name="target">The target dependency object.</param> + /// <param name="dependencyProperty">The dependency property.</param> + public static void Unbind(this DependencyObject target, DependencyProperty dependencyProperty) + { + BindingOperations.ClearBinding(target, dependencyProperty); + } +} diff --git a/Software/Visual Studio/Tango.Core/ExtensionMethods/EnumExtensions.cs b/Software/Visual Studio/Tango.Core/ExtensionMethods/EnumExtensions.cs new file mode 100644 index 000000000..106dd4f44 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ExtensionMethods/EnumExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +public static class EnumExtensions +{ + /// <summary> + /// Gets the Enum value description. + /// </summary> + /// <param name="value">The value.</param> + /// <returns></returns> + public static String ToDescription(this Enum value) + { + FieldInfo fi = value.GetType().GetField(value.ToString()); + + DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); + + if (attributes != null && + attributes.Length > 0) + return attributes[0].Description; + else + return value.ToString(); + } + + public static int ToInt32(this Enum value) + { + return (int)((object)value); + } +} diff --git a/Software/Visual Studio/Tango.Core/ExtensionMethods/IParameterizedExtensions.cs b/Software/Visual Studio/Tango.Core/ExtensionMethods/IParameterizedExtensions.cs new file mode 100644 index 000000000..5ee853f35 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ExtensionMethods/IParameterizedExtensions.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core; + +/// <summary> +/// Contains extension methods for <see cref="IParameterized"/>. +/// </summary> +public static class IParameterizedExtensions +{ + /// <summary> + /// Creates an observable collection of the parameterized object. + /// </summary> + /// <param name="instance">The instance.</param> + /// <param name="mode">The parameters update mode.</param> + /// <returns></returns> + public static ObservableCollection<ParameterItem> CreateParametersCollection(this IParameterized instance, ParameterItemMode mode) + { + var ps = new ObservableCollection<ParameterItem>(); + + int index = 0; + + List<Type> types = new List<Type>(); + Type currentType = instance.GetType(); + + while (true) + { + if (typeof(IParameterized).IsAssignableFrom(currentType) && currentType != typeof(IParameterized)) + { + types.Add(currentType); + currentType = currentType.BaseType; + } + else + { + break; + } + } + + List<PropertyInfo> properties = new List<PropertyInfo>(); + + foreach (var type in types) + { + foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + { + var paramAtt = prop.GetCustomAttributes(typeof(ParameterItemAttribute), false).Cast<ParameterItemAttribute>().FirstOrDefault(); + var ignore = prop.GetCustomAttributes(typeof(ParameterIgnoreAttribute), false).Cast<ParameterIgnoreAttribute>().FirstOrDefault(); + + if (ignore == null && !properties.Exists(x => x.Name == prop.Name)) + { + var item = instance.CreateParameterItem(prop, paramAtt, index++, mode); + ps.Add(item); + properties.Add(prop); + } + } + } + + return ps; + } + + /// <summary> + /// Creates the parameter item. + /// </summary> + /// <param name="instance">The instance.</param> + /// <param name="propertyInfo">The property information.</param> + /// <param name="attribute">The attribute.</param> + /// <param name="index">The index.</param> + /// <param name="mode">The mode.</param> + /// <returns></returns> + public static ParameterItem CreateParameterItem(this IParameterized instance, PropertyInfo propertyInfo, ParameterItemAttribute attribute, int index, ParameterItemMode mode) + { + ParameterItem item = new ParameterItem(); + item.Name = propertyInfo.Name.ToTitle(); + item.Index = index; + item.Type = propertyInfo.PropertyType; + item.Value = propertyInfo.GetValue(instance, null); + + if (attribute != null) + { + item.Minimum = attribute.Minimum; + item.Maximum = attribute.Maximum; + item.CustomEditorTypeName = attribute.CustomEditorTypeName; + item.ExtraObject = attribute.ExtraObject; + + if (attribute.Name != null) + { + item.Name = attribute.Name; + } + } + + if (mode == ParameterItemMode.Event) + { + item.ParameterValueChanged += (sender, e) => + { + propertyInfo.SetValue(instance, e.Value); + }; + } + else if (mode == ParameterItemMode.Binding) + { + item.Bind(ParameterItem.ValueProperty, instance as DependencyObject, propertyInfo.Name, System.Windows.Data.BindingMode.TwoWay); + } + + return item; + } + + /// <summary> + /// Creates the parameter item. + /// </summary> + /// <param name="instance">The instance.</param> + /// <param name="propertyName">Name of the property.</param> + /// <param name="attribute">The attribute.</param> + /// <param name="index">The index.</param> + /// <param name="mode">The mode.</param> + /// <returns></returns> + public static ParameterItem CreateParameterItem(this IParameterized instance, String propertyName, ParameterItemAttribute attribute, int index, ParameterItemMode mode) + { + return instance.CreateParameterItem(instance.GetType().GetProperty(propertyName), attribute, index, mode); + } +} + diff --git a/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs b/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs index 049c9c4af..5699d27a0 100644 --- a/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs +++ b/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs @@ -2,10 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; public static class StringExtensions { + private static Regex titleRegEx; + + /// <summary> + /// Initializes the <see cref="StringExtensions"/> class. + /// </summary> + static StringExtensions() + { + titleRegEx = new Regex(@" + (?<=[A-Z])(?=[A-Z][a-z]) | + (?<=[^A-Z])(?=[A-Z]) | + (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace); + } + /// <summary> /// Normal ToString conversion with null checking. /// </summary> @@ -25,4 +39,14 @@ public static class StringExtensions { return str.Split(new[] { '\r', '\n' }).ToList(); } + + /// <summary> + /// Formats the string to title style. + /// </summary> + /// <param name="str">The string.</param> + /// <returns></returns> + public static String ToTitle(this String str) + { + return titleRegEx.Replace(str, " "); + } } diff --git a/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs b/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs index 405020e66..d3322514a 100644 --- a/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs +++ b/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace Tango.Core.Helpers +namespace Tango.SharedUI.Helpers { public static class AssemblyHelper { diff --git a/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs b/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs index fa52eb42b..c375722e7 100644 --- a/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs +++ b/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Tango.Core.Helpers +namespace Tango.SharedUI.Helpers { public static class PathHelper { diff --git a/Software/Visual Studio/Tango.Core/IParameterized.cs b/Software/Visual Studio/Tango.Core/IParameterized.cs new file mode 100644 index 000000000..e6f36b4c6 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/IParameterized.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Core +{ + /// <summary> + /// Represents a component that exposes some of it's properties as an observable collection of <see cref="ParameterItem"/> which can be bound to UI controls. + /// </summary> + public interface IParameterized + { + /// <summary> + /// Gets a bind-able observable collection of the component properties. + /// </summary> + [ParameterIgnore] + ReadOnlyObservableCollection<ParameterItem> Parameters { get; set; } + } +} diff --git a/Software/Visual Studio/Tango.Core/ParameterIgnoreAttribute.cs b/Software/Visual Studio/Tango.Core/ParameterIgnoreAttribute.cs new file mode 100644 index 000000000..0bbca6a06 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ParameterIgnoreAttribute.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Core +{ + /// <summary> + /// Represents an attribute for specifying properties to ignore as parameters. + /// </summary> + /// <seealso cref="System.Attribute" /> + public class ParameterIgnoreAttribute : Attribute + { + + } +} diff --git a/Software/Visual Studio/Tango.Core/ParameterItem.cs b/Software/Visual Studio/Tango.Core/ParameterItem.cs new file mode 100644 index 000000000..53a3df269 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ParameterItem.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.Core +{ + /// <summary> + /// Represents a component parameter name and value which can be bound to UI elements. + /// </summary> + /// <seealso cref="System.Windows.DependencyObject" /> + public class ParameterItem : DependencyObject + { + internal bool disableParamEvent; + + /// <summary> + /// Occurs when the parameter value has changed. + /// </summary> + public event EventHandler<ParameterItem> ParameterValueChanged; + + /// <summary> + /// Gets or sets the parameter index. + /// </summary> + public int Index + { + get { return (int)GetValue(IndexProperty); } + set { SetValue(IndexProperty, value); } + } + public static readonly DependencyProperty IndexProperty = + DependencyProperty.Register("Index", typeof(int), typeof(ParameterItem), new PropertyMetadata(0)); + + /// <summary> + /// Gets or sets the parameter value type. + /// </summary> + public Type Type + { + get { return (Type)GetValue(TypeProperty); } + set { SetValue(TypeProperty, value); } + } + public static readonly DependencyProperty TypeProperty = + DependencyProperty.Register("Type", typeof(Type), typeof(ParameterItem), new PropertyMetadata(typeof(double))); + + + /// <summary> + /// Gets or sets the parameter name. + /// </summary> + public String Name + { + get { return (String)GetValue(NameProperty); } + set { SetValue(NameProperty, value); } + } + public static readonly DependencyProperty NameProperty = + DependencyProperty.Register("Name", typeof(String), typeof(ParameterItem), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the current parameter value. + /// </summary> + public object Value + { + get { return (object)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + public static readonly DependencyProperty ValueProperty = + DependencyProperty.Register("Value", typeof(object), typeof(ParameterItem), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged))); + + + /// <summary> + /// Gets or sets the minimum parameter value. + /// </summary> + public object Minimum + { + get { return (object)GetValue(MinimumProperty); } + set { SetValue(MinimumProperty, value); } + } + public static readonly DependencyProperty MinimumProperty = + DependencyProperty.Register("Minimum", typeof(object), typeof(ParameterItem), new PropertyMetadata(0.0d)); + + + /// <summary> + /// Gets or sets the maximum parameter value. + /// </summary> + public object Maximum + { + get { return (object)GetValue(MaximumProperty); } + set { SetValue(MaximumProperty, value); } + } + public static readonly DependencyProperty MaximumProperty = + DependencyProperty.Register("Maximum", typeof(object), typeof(ParameterItem), new PropertyMetadata(1.0d)); + + + /// <summary> + /// Gets or sets an optional extra object. + /// </summary> + public object ExtraObject + { + get { return (object)GetValue(ExtraObjectProperty); } + set { SetValue(ExtraObjectProperty, value); } + } + public static readonly DependencyProperty ExtraObjectProperty = + DependencyProperty.Register("ExtraObject", typeof(object), typeof(ParameterItem), new PropertyMetadata(null)); + + + /// <summary> + /// Gets or sets an optional custom editor. + /// </summary> + public String CustomEditorTypeName + { + get { return (String)GetValue(CustomEditorTypeNameProperty); } + set { SetValue(CustomEditorTypeNameProperty, value); } + } + public static readonly DependencyProperty CustomEditorTypeNameProperty = + DependencyProperty.Register("CustomEditorType", typeof(String), typeof(ParameterItem), new PropertyMetadata(null)); + + + /// <summary> + /// Gets a value indicating whether this instance requires custom editor. + /// </summary> + public bool HasCustomEditor + { + get { return CustomEditorTypeName != null; } + } + + /// <summary> + /// Called when value has changed. + /// </summary> + /// <param name="d">The d.</param> + /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> + private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as ParameterItem).OnParameterChanged(); + } + + /// <summary> + /// Called when the parameter value has changed. + /// </summary> + protected virtual void OnParameterChanged() + { + if (!disableParamEvent) + { + if (ParameterValueChanged != null) ParameterValueChanged(this, this); + } + } + + /// <summary> + /// Returns a <see cref="System.String" /> that represents this instance. + /// </summary> + /// <returns> + /// A <see cref="System.String" /> that represents this instance. + /// </returns> + public override string ToString() + { + return Name; + } + } +} diff --git a/Software/Visual Studio/Tango.Core/ParameterItemAttribute.cs b/Software/Visual Studio/Tango.Core/ParameterItemAttribute.cs new file mode 100644 index 000000000..68405fe64 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ParameterItemAttribute.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Core +{ + /// <summary> + /// Represents a parameter item attribute for used for default, min and max values definition of properties. + /// </summary> + /// <seealso cref="System.Attribute" /> + public class ParameterItemAttribute : Attribute + { + /// <summary> + /// Gets or sets the custom parameter name. + /// </summary> + public String Name { get; set; } + + /// <summary> + /// Gets or sets the default value. + /// </summary> + public object Default { get; set; } + + /// <summary> + /// Gets or sets the minimum value. + /// </summary> + public object Minimum { get; set; } + + /// <summary> + /// Gets or sets the maximum value. + /// </summary> + public object Maximum { get; set; } + + /// <summary> + /// Gets or sets an optional extra object. + /// </summary> + public object ExtraObject { get; set; } + + /// <summary> + /// Gets or sets an optional custom editor type name. + /// </summary> + public String CustomEditorTypeName { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + public ParameterItemAttribute() + { + Default = null; + Minimum = 0.0d; + Maximum = 1.0d; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="minimumValue">The minimum value.</param> + /// <param name="maximumValue">The maximum value.</param> + /// <param name="defaultValue">The default value.</param> + public ParameterItemAttribute(String name, object minimumValue, object maximumValue, object defaultValue) : this() + { + Name = name; + Default = defaultValue; + Minimum = minimumValue; + Maximum = maximumValue; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="minimumValue">The minimum value.</param> + /// <param name="maximumValue">The maximum value.</param> + public ParameterItemAttribute(String name, object minimumValue, double maximumValue) : this(name, minimumValue, maximumValue, null) + { + + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="minimumValue">The minimum value.</param> + /// <param name="maximumValue">The maximum value.</param> + public ParameterItemAttribute(object minimumValue, object maximumValue) : this() + { + Minimum = minimumValue; + Maximum = maximumValue; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="customParameterEditorTypeName">Type of the custom parameter editor type name.</param> + public ParameterItemAttribute(String customParameterEditorTypeName) : this() + { + CustomEditorTypeName = customParameterEditorTypeName; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="customParameterEditorTypeName">Name of the custom parameter editor type.</param> + /// <param name="minimumValue">The minimum value.</param> + /// <param name="maximumValue">The maximum value.</param> + /// <param name="defaultValue">The default value.</param> + /// <param name="extraObject">The extra object.</param> + public ParameterItemAttribute(String name, String customParameterEditorTypeName, object minimumValue, object maximumValue, object defaultValue, object extraObject) : this() + { + Name = name; + Minimum = minimumValue; + Maximum = maximumValue; + Default = defaultValue; + CustomEditorTypeName = customParameterEditorTypeName; + ExtraObject = extraObject; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemAttribute"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="customParameterEditorTypeName">Custom parameter editor type.</param> + /// <param name="minimumValue">The minimum value.</param> + /// <param name="maximumValue">The maximum value.</param> + /// <param name="defaultValue">The default value.</param> + /// <param name="extraObject">The extra object.</param> + public ParameterItemAttribute(String name, Type customParameterEditorType, object minimumValue, object maximumValue, object defaultValue, object extraObject) + : this() + { + Name = name; + Minimum = minimumValue; + Maximum = maximumValue; + Default = defaultValue; + CustomEditorTypeName = customParameterEditorType.AssemblyQualifiedName; + ExtraObject = extraObject; + } + } +} diff --git a/Software/Visual Studio/Tango.Core/ParameterItemMode.cs b/Software/Visual Studio/Tango.Core/ParameterItemMode.cs new file mode 100644 index 000000000..71cb0f139 --- /dev/null +++ b/Software/Visual Studio/Tango.Core/ParameterItemMode.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Core +{ + /// <summary> + /// Represents a <see cref="ParameterItem"/> update mode. + /// </summary> + public enum ParameterItemMode + { + /// <summary> + /// Update by binding. + /// </summary> + Binding, + /// <summary> + /// Update by event. + /// </summary> + Event + } +} diff --git a/Software/Visual Studio/Tango.Core/Tango.Core.csproj b/Software/Visual Studio/Tango.Core/Tango.Core.csproj index 7b469bfdc..012f95f5e 100644 --- a/Software/Visual Studio/Tango.Core/Tango.Core.csproj +++ b/Software/Visual Studio/Tango.Core/Tango.Core.csproj @@ -35,6 +35,7 @@ <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Windows" /> + <Reference Include="System.Xaml" /> <Reference Include="System.Xml.Linq" /> <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> @@ -47,9 +48,17 @@ <Compile Include="..\Versioning\GlobalVersionInfo.cs"> <Link>GlobalVersionInfo.cs</Link> </Compile> + <Compile Include="ExtensionMethods\DependencyObjectExtensions.cs" /> + <Compile Include="ExtensionMethods\EnumExtensions.cs" /> + <Compile Include="ExtensionMethods\IParameterizedExtensions.cs" /> <Compile Include="ExtensionMethods\StringExtensions.cs" /> <Compile Include="Helpers\AssemblyHelper.cs" /> <Compile Include="Helpers\PathHelper.cs" /> + <Compile Include="IParameterized.cs" /> + <Compile Include="ParameterIgnoreAttribute.cs" /> + <Compile Include="ParameterItem.cs" /> + <Compile Include="ParameterItemAttribute.cs" /> + <Compile Include="ParameterItemMode.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> diff --git a/Software/Visual Studio/Tango.Emulations/Emulators/MachineEmulator.cs b/Software/Visual Studio/Tango.Emulations/Emulators/MachineEmulator.cs index 8c986cb95..c84a3e3ee 100644 --- a/Software/Visual Studio/Tango.Emulations/Emulators/MachineEmulator.cs +++ b/Software/Visual Studio/Tango.Emulations/Emulators/MachineEmulator.cs @@ -51,17 +51,32 @@ namespace Tango.Emulations.Emulators { switch (container.Type) { - case MessageType.Stub1Request: + case MessageType.CalculateRequest: Task.Factory.StartNew(() => { - Thread.Sleep(1000); - var request = MessageFactory.ParseContainer<Stub1Request>(container); - var response = MessageFactory.CreateContainer<Stub1Response>(container.Token); + Thread.Sleep(2000); + var request = MessageFactory.ParseContainer<CalculateRequest>(container); + var response = MessageFactory.CreateContainer<CalculateResponse>(container.Token); response.Message.Sum = request.A + request.B; - response.Container.Token = container.Token; Transporter.SendResponse(response); }); break; + case MessageType.ProgressRequest: + + var r = MessageFactory.ParseContainer<ProgressRequest>(container); + + Task.Factory.StartNew(() => + { + for (int i = 0; i < 10; i++) + { + Thread.Sleep(500); + var res = MessageFactory.CreateContainer<ProgressResponse>(container.Token); + res.Message.Progress = i; + Transporter.SendResponse(res); + } + }); + + break; } } diff --git a/Software/Visual Studio/Tango.PMR/Common/MessageType.cs b/Software/Visual Studio/Tango.PMR/Common/MessageType.cs index c2ca7a47d..0012627bb 100644 --- a/Software/Visual Studio/Tango.PMR/Common/MessageType.cs +++ b/Software/Visual Studio/Tango.PMR/Common/MessageType.cs @@ -22,10 +22,11 @@ namespace Tango.PMR.Common { static MessageTypeReflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "ChFNZXNzYWdlVHlwZS5wcm90bxIQVGFuZ28uUE1SLkNvbW1vbipRCgtNZXNz", - "YWdlVHlwZRIHCgNSR0IQABIHCgNKb2IQARILCgdTZWdtZW50EAISEAoMU3R1", - "YjFSZXF1ZXN0EAMSEQoNU3R1YjFSZXNwb25zZRAEQhwKGmNvbS50d2luZS50", - "YW5nby5wbXIuY29tbW9uYgZwcm90bzM=")); + "ChFNZXNzYWdlVHlwZS5wcm90bxIQVGFuZ28uUE1SLkNvbW1vbiqEAQoLTWVz", + "c2FnZVR5cGUSBwoDUkdCEAASBwoDSm9iEAESCwoHU2VnbWVudBACEhQKEENh", + "bGN1bGF0ZVJlcXVlc3QQAxIVChFDYWxjdWxhdGVSZXNwb25zZRAEEhMKD1By", + "b2dyZXNzUmVxdWVzdBAFEhQKEFByb2dyZXNzUmVzcG9uc2UQBkIcChpjb20u", + "dHdpbmUudGFuZ28ucG1yLmNvbW1vbmIGcHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Tango.PMR.Common.MessageType), }, null)); @@ -38,8 +39,10 @@ namespace Tango.PMR.Common { [pbr::OriginalName("RGB")] Rgb = 0, [pbr::OriginalName("Job")] Job = 1, [pbr::OriginalName("Segment")] Segment = 2, - [pbr::OriginalName("Stub1Request")] Stub1Request = 3, - [pbr::OriginalName("Stub1Response")] Stub1Response = 4, + [pbr::OriginalName("CalculateRequest")] CalculateRequest = 3, + [pbr::OriginalName("CalculateResponse")] CalculateResponse = 4, + [pbr::OriginalName("ProgressRequest")] ProgressRequest = 5, + [pbr::OriginalName("ProgressResponse")] ProgressResponse = 6, } #endregion diff --git a/Software/Visual Studio/Tango.PMR/Stubs/Stub1.cs b/Software/Visual Studio/Tango.PMR/Stubs/Calculate.cs index 7d4960e9b..75aa074e1 100644 --- a/Software/Visual Studio/Tango.PMR/Stubs/Stub1.cs +++ b/Software/Visual Studio/Tango.PMR/Stubs/Calculate.cs @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: Stub1.proto +// source: Calculate.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code @@ -9,41 +9,42 @@ using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Tango.PMR.Stubs { - /// <summary>Holder for reflection information generated from Stub1.proto</summary> - public static partial class Stub1Reflection { + /// <summary>Holder for reflection information generated from Calculate.proto</summary> + public static partial class CalculateReflection { #region Descriptor - /// <summary>File descriptor for Stub1.proto</summary> + /// <summary>File descriptor for Calculate.proto</summary> public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static Stub1Reflection() { + static CalculateReflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "CgtTdHViMS5wcm90bxIPVGFuZ28uUE1SLlN0dWJzIiQKDFN0dWIxUmVxdWVz", - "dBIJCgFBGAEgASgFEgkKAUIYAiABKAUiHAoNU3R1YjFSZXNwb25zZRILCgNT", - "dW0YASABKAVCGwoZY29tLnR3aW5lLnRhbmdvLnBtci5zdHVic2IGcHJvdG8z")); + "Cg9DYWxjdWxhdGUucHJvdG8SD1RhbmdvLlBNUi5TdHVicyIoChBDYWxjdWxh", + "dGVSZXF1ZXN0EgkKAUEYASABKAESCQoBQhgCIAEoASIgChFDYWxjdWxhdGVS", + "ZXNwb25zZRILCgNTdW0YASABKAFCGwoZY29tLnR3aW5lLnRhbmdvLnBtci5z", + "dHVic2IGcHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.Stub1Request), global::Tango.PMR.Stubs.Stub1Request.Parser, new[]{ "A", "B" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.Stub1Response), global::Tango.PMR.Stubs.Stub1Response.Parser, new[]{ "Sum" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.CalculateRequest), global::Tango.PMR.Stubs.CalculateRequest.Parser, new[]{ "A", "B" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.CalculateResponse), global::Tango.PMR.Stubs.CalculateResponse.Parser, new[]{ "Sum" }, null, null, null) })); } #endregion } #region Messages - public sealed partial class Stub1Request : pb::IMessage<Stub1Request> { - private static readonly pb::MessageParser<Stub1Request> _parser = new pb::MessageParser<Stub1Request>(() => new Stub1Request()); + public sealed partial class CalculateRequest : pb::IMessage<CalculateRequest> { + private static readonly pb::MessageParser<CalculateRequest> _parser = new pb::MessageParser<CalculateRequest>(() => new CalculateRequest()); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser<Stub1Request> Parser { get { return _parser; } } + public static pb::MessageParser<CalculateRequest> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { - get { return global::Tango.PMR.Stubs.Stub1Reflection.Descriptor.MessageTypes[0]; } + get { return global::Tango.PMR.Stubs.CalculateReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -52,28 +53,28 @@ namespace Tango.PMR.Stubs { } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Request() { + public CalculateRequest() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Request(Stub1Request other) : this() { + public CalculateRequest(CalculateRequest other) : this() { a_ = other.a_; b_ = other.b_; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Request Clone() { - return new Stub1Request(this); + public CalculateRequest Clone() { + return new CalculateRequest(this); } /// <summary>Field number for the "A" field.</summary> public const int AFieldNumber = 1; - private int a_; + private double a_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int A { + public double A { get { return a_; } set { a_ = value; @@ -82,9 +83,9 @@ namespace Tango.PMR.Stubs { /// <summary>Field number for the "B" field.</summary> public const int BFieldNumber = 2; - private int b_; + private double b_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int B { + public double B { get { return b_; } set { b_ = value; @@ -93,11 +94,11 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { - return Equals(other as Stub1Request); + return Equals(other as CalculateRequest); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Stub1Request other) { + public bool Equals(CalculateRequest other) { if (ReferenceEquals(other, null)) { return false; } @@ -112,8 +113,8 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; - if (A != 0) hash ^= A.GetHashCode(); - if (B != 0) hash ^= B.GetHashCode(); + if (A != 0D) hash ^= A.GetHashCode(); + if (B != 0D) hash ^= B.GetHashCode(); return hash; } @@ -124,37 +125,37 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { - if (A != 0) { - output.WriteRawTag(8); - output.WriteInt32(A); + if (A != 0D) { + output.WriteRawTag(9); + output.WriteDouble(A); } - if (B != 0) { - output.WriteRawTag(16); - output.WriteInt32(B); + if (B != 0D) { + output.WriteRawTag(17); + output.WriteDouble(B); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; - if (A != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(A); + if (A != 0D) { + size += 1 + 8; } - if (B != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(B); + if (B != 0D) { + size += 1 + 8; } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Stub1Request other) { + public void MergeFrom(CalculateRequest other) { if (other == null) { return; } - if (other.A != 0) { + if (other.A != 0D) { A = other.A; } - if (other.B != 0) { + if (other.B != 0D) { B = other.B; } } @@ -167,12 +168,12 @@ namespace Tango.PMR.Stubs { default: input.SkipLastField(); break; - case 8: { - A = input.ReadInt32(); + case 9: { + A = input.ReadDouble(); break; } - case 16: { - B = input.ReadInt32(); + case 17: { + B = input.ReadDouble(); break; } } @@ -181,14 +182,14 @@ namespace Tango.PMR.Stubs { } - public sealed partial class Stub1Response : pb::IMessage<Stub1Response> { - private static readonly pb::MessageParser<Stub1Response> _parser = new pb::MessageParser<Stub1Response>(() => new Stub1Response()); + public sealed partial class CalculateResponse : pb::IMessage<CalculateResponse> { + private static readonly pb::MessageParser<CalculateResponse> _parser = new pb::MessageParser<CalculateResponse>(() => new CalculateResponse()); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser<Stub1Response> Parser { get { return _parser; } } + public static pb::MessageParser<CalculateResponse> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { - get { return global::Tango.PMR.Stubs.Stub1Reflection.Descriptor.MessageTypes[1]; } + get { return global::Tango.PMR.Stubs.CalculateReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -197,27 +198,27 @@ namespace Tango.PMR.Stubs { } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Response() { + public CalculateResponse() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Response(Stub1Response other) : this() { + public CalculateResponse(CalculateResponse other) : this() { sum_ = other.sum_; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Stub1Response Clone() { - return new Stub1Response(this); + public CalculateResponse Clone() { + return new CalculateResponse(this); } /// <summary>Field number for the "Sum" field.</summary> public const int SumFieldNumber = 1; - private int sum_; + private double sum_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int Sum { + public double Sum { get { return sum_; } set { sum_ = value; @@ -226,11 +227,11 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { - return Equals(other as Stub1Response); + return Equals(other as CalculateResponse); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Stub1Response other) { + public bool Equals(CalculateResponse other) { if (ReferenceEquals(other, null)) { return false; } @@ -244,7 +245,7 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; - if (Sum != 0) hash ^= Sum.GetHashCode(); + if (Sum != 0D) hash ^= Sum.GetHashCode(); return hash; } @@ -255,27 +256,27 @@ namespace Tango.PMR.Stubs { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { - if (Sum != 0) { - output.WriteRawTag(8); - output.WriteInt32(Sum); + if (Sum != 0D) { + output.WriteRawTag(9); + output.WriteDouble(Sum); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; - if (Sum != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(Sum); + if (Sum != 0D) { + size += 1 + 8; } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Stub1Response other) { + public void MergeFrom(CalculateResponse other) { if (other == null) { return; } - if (other.Sum != 0) { + if (other.Sum != 0D) { Sum = other.Sum; } } @@ -288,8 +289,8 @@ namespace Tango.PMR.Stubs { default: input.SkipLastField(); break; - case 8: { - Sum = input.ReadInt32(); + case 9: { + Sum = input.ReadDouble(); break; } } diff --git a/Software/Visual Studio/Tango.PMR/Stubs/Progress.cs b/Software/Visual Studio/Tango.PMR/Stubs/Progress.cs new file mode 100644 index 000000000..2a00e15de --- /dev/null +++ b/Software/Visual Studio/Tango.PMR/Stubs/Progress.cs @@ -0,0 +1,249 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: Progress.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Tango.PMR.Stubs { + + /// <summary>Holder for reflection information generated from Progress.proto</summary> + public static partial class ProgressReflection { + + #region Descriptor + /// <summary>File descriptor for Progress.proto</summary> + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ProgressReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Cg5Qcm9ncmVzcy5wcm90bxIPVGFuZ28uUE1SLlN0dWJzIhEKD1Byb2dyZXNz", + "UmVxdWVzdCIkChBQcm9ncmVzc1Jlc3BvbnNlEhAKCFByb2dyZXNzGAEgASgB", + "QhsKGWNvbS50d2luZS50YW5nby5wbXIuc3R1YnNiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.ProgressRequest), global::Tango.PMR.Stubs.ProgressRequest.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Stubs.ProgressResponse), global::Tango.PMR.Stubs.ProgressResponse.Parser, new[]{ "Progress" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class ProgressRequest : pb::IMessage<ProgressRequest> { + private static readonly pb::MessageParser<ProgressRequest> _parser = new pb::MessageParser<ProgressRequest>(() => new ProgressRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser<ProgressRequest> Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Stubs.ProgressReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressRequest(ProgressRequest other) : this() { + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressRequest Clone() { + return new ProgressRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ProgressRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ProgressRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ProgressRequest other) { + if (other == null) { + return; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + } + } + } + + } + + public sealed partial class ProgressResponse : pb::IMessage<ProgressResponse> { + private static readonly pb::MessageParser<ProgressResponse> _parser = new pb::MessageParser<ProgressResponse>(() => new ProgressResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser<ProgressResponse> Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Stubs.ProgressReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressResponse(ProgressResponse other) : this() { + progress_ = other.progress_; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ProgressResponse Clone() { + return new ProgressResponse(this); + } + + /// <summary>Field number for the "Progress" field.</summary> + public const int ProgressFieldNumber = 1; + private double progress_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double Progress { + get { return progress_; } + set { + progress_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ProgressResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ProgressResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Progress != other.Progress) return false; + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Progress != 0D) hash ^= Progress.GetHashCode(); + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Progress != 0D) { + output.WriteRawTag(9); + output.WriteDouble(Progress); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Progress != 0D) { + size += 1 + 8; + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ProgressResponse other) { + if (other == null) { + return; + } + if (other.Progress != 0D) { + Progress = other.Progress; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + Progress = input.ReadDouble(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/Software/Visual Studio/Tango.PMR/Tango.PMR.csproj b/Software/Visual Studio/Tango.PMR/Tango.PMR.csproj index 8039b352a..dd873fe90 100644 --- a/Software/Visual Studio/Tango.PMR/Tango.PMR.csproj +++ b/Software/Visual Studio/Tango.PMR/Tango.PMR.csproj @@ -53,7 +53,8 @@ <Compile Include="Jobs\Segment.cs" /> <Compile Include="MessageFactory.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Stubs\Stub1.cs" /> + <Compile Include="Stubs\Calculate.cs" /> + <Compile Include="Stubs\Progress.cs" /> <Compile Include="TangoMessage.cs" /> </ItemGroup> <ItemGroup> diff --git a/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs b/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs index 55f0cf77f..80d8961c3 100644 --- a/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs +++ b/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using Tango.Core.Helpers; +using Tango.SharedUI.Helpers; using Tango.Logging; namespace Tango.Protobuf.Compilers diff --git a/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs b/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs index c77199c21..c047b8680 100644 --- a/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs +++ b/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs @@ -6,8 +6,8 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using Tango.Core; -using Tango.Core.Helpers; +using Tango.SharedUI; +using Tango.SharedUI.Helpers; using Tango.Logging; namespace Tango.Protobuf diff --git a/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml b/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml new file mode 100644 index 000000000..33e3758a5 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml @@ -0,0 +1,11 @@ +<UserControl x:Class="Tango.SharedUI.Controls.MultiTransitionControl" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="300" ClipToBounds="True"> + <Grid x:Name="mainGrid"> + + </Grid> +</UserControl> diff --git a/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml.cs b/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml.cs new file mode 100644 index 000000000..83cb49de2 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Controls/MultiTransitionControl.xaml.cs @@ -0,0 +1,473 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +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.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.SharedUI.Controls +{ + /// <summary> + /// Represents a control for holding a list of content controls and creates transition effects between them. + /// </summary> + public partial class MultiTransitionControl : UserControl + { + private int index; + private bool freezeAnimation; + private ContentControl element1 = null; + private ContentControl element2 = null; + private ContentControl fromElement; + private ContentControl toElement; + private Action navigationCompleteAction; + private bool _loaded; + + #region Events + /// <summary> + /// Occurs when the transition has completed. + /// </summary> + public event Action<MultiTransitionControl> TransitionComplete; + + #endregion + + #region Constructors + + /// <summary> + /// Initialize a new instance of MultiTransitionControl. + /// </summary> + public MultiTransitionControl() + { + Controls = new List<ContentControl>(); + + index = 0; + InitializeComponent(); + this.Loaded += MultiTransitionControl_Loaded; + } + + #endregion + + #region Event Handlers + + private void MultiTransitionControl_Loaded(object sender, RoutedEventArgs e) + { + if (!_loaded) + { + foreach (ContentControl control in Controls) + { + control.Visibility = System.Windows.Visibility.Hidden; + mainGrid.Children.Add(control); + } + + if (Controls.Count > 0) + { + Controls[0].Visibility = System.Windows.Visibility.Visible; + SelectedControl = Controls[0]; + fromElement = SelectedControl; + } + + _loaded = true; + } + } + + private void ani_BackCompleted(object sender, EventArgs e) + { + fromElement = toElement; + toElement = null; + freezeAnimation = true; + this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null); + Mix = 0; + index++; + freezeAnimation = false; + IsAnimating = false; + + OnTransitionCompleted(); + } + + private void ani_NextCompleted(object sender, EventArgs e) + { + fromElement = toElement; + toElement = null; + freezeAnimation = true; + this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null); + Mix = 0; + index++; + freezeAnimation = false; + IsAnimating = false; + + OnTransitionCompleted(); + } + + #endregion + + #region Properties + + /// <summary> + /// Gets or sets the available content controls nested in the MultiTransitionControl. + /// </summary> + public List<ContentControl> Controls { get; set; } + + /// <summary> + /// Gets or sets the transition style. + /// </summary> + public TransitionTypeEnum TransitionType + { + get { return (TransitionTypeEnum)GetValue(TransitionTypeProperty); } + set { SetValue(TransitionTypeProperty, value); } + } + public static readonly DependencyProperty TransitionTypeProperty = + DependencyProperty.Register("TransitionType", typeof(TransitionTypeEnum), typeof(MultiTransitionControl), new PropertyMetadata(TransitionTypeEnum.Fade) { PropertyChangedCallback = new PropertyChangedCallback(TransitionTypeChanged) }); + private static void TransitionTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as MultiTransitionControl).ResetTransformation(); + } + + /// <summary> + /// This is where the actual transition occurs. + /// </summary> + private double Mix + { + get { return (double)GetValue(MixProperty); } + set + { + SetValue(MixProperty, value); + if (!freezeAnimation) + { + UpdateMix(value); + } + } + } + private static readonly DependencyProperty MixProperty = + DependencyProperty.Register("Mix", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(new PropertyChangedCallback(MixChanged))); + private static void MixChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + MultiTransitionControl tr = d as MultiTransitionControl; + double value = (double)e.NewValue; + tr.UpdateMix(value); + } + + + /// <summary> + /// Gets or sets whether to always include a cross fade transition along with the selected transition style. + /// </summary> + public bool AlwaysFade + { + get { return (bool)GetValue(AlwaysFadeProperty); } + set { SetValue(AlwaysFadeProperty, value); } + } + public static readonly DependencyProperty AlwaysFadeProperty = + DependencyProperty.Register("AlwaysFade", typeof(bool), typeof(MultiTransitionControl), new PropertyMetadata(false)); + + + /// <summary> + /// Gets or sets the interval in milliseconds for the transition to complete. + /// </summary> + public int AnimationTime + { + get { return (int)GetValue(AnimationTimeProperty); } + set { SetValue(AnimationTimeProperty, value); } + } + public static readonly DependencyProperty AnimationTimeProperty = + DependencyProperty.Register("AnimationTime", typeof(int), typeof(MultiTransitionControl), new PropertyMetadata(1000)); + + + /// <summary> + /// Gets or sets the transition 'ease in' time. + /// </summary> + public double AnimationAcceleration + { + get { return (double)GetValue(AnimationAccelerationProperty); } + set { SetValue(AnimationAccelerationProperty, value); } + } + public static readonly DependencyProperty AnimationAccelerationProperty = + DependencyProperty.Register("AnimationAcceleration", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(0.5)); + + + /// <summary> + /// Gets or sets the transition 'ease out' time. + /// </summary> + public double AnimationDeceleration + { + get { return (double)GetValue(AnimationDecelerationProperty); } + set { SetValue(AnimationDecelerationProperty, value); } + } + public static readonly DependencyProperty AnimationDecelerationProperty = + DependencyProperty.Register("AnimationDeceleration", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(0.5)); + + + /// <summary> + /// Gets or sets whether a transition is taking place at the moment. + /// </summary> + public bool IsAnimating + { + get { return (bool)GetValue(IsAnimatingProperty); } + private set { SetValue(IsAnimatingProperty, value); } + } + public static readonly DependencyProperty IsAnimatingProperty = + DependencyProperty.Register("IsAnimating", typeof(bool), typeof(MultiTransitionControl), new PropertyMetadata(false)); + + + /// <summary> + /// Gets or sets currently visible content control. + /// </summary> + public ContentControl SelectedControl + { + get { return (ContentControl)GetValue(SelectedControlProperty); } + set { SetValue(SelectedControlProperty, value); } + } + public static readonly DependencyProperty SelectedControlProperty = + DependencyProperty.Register("SelectedControl", typeof(ContentControl), typeof(MultiTransitionControl), new PropertyMetadata(null)); + + #endregion + + #region Methods + + /// <summary> + /// Updates the mix. + /// </summary> + /// <param name="value">The value.</param> + private void UpdateMix(double value) + { + if (freezeAnimation) return; + + if (element1 == null || element2 == null) + { + return; + } + + element1.Visibility = System.Windows.Visibility.Visible; + element2.Visibility = System.Windows.Visibility.Visible; + + if (TransitionType == TransitionTypeEnum.Fade) + { + element1.RenderTransform = null; + element2.RenderTransform = null; + element1.Opacity = value; + element2.Opacity = 1 - value; + return; + } + else if (TransitionType == TransitionTypeEnum.Slide) + { + double v = value * 100; + v = (v * this.ActualWidth) / 100; + element2.RenderTransform = new TranslateTransform(v, 0); + element1.RenderTransform = new TranslateTransform(v - this.ActualWidth, 0); + } + else if (TransitionType == TransitionTypeEnum.Zoom) + { + element1.RenderTransformOrigin = new Point(0.5, 0.5); + element2.RenderTransformOrigin = new Point(0.5, 0.5); + element1.RenderTransform = new ScaleTransform(value, value); + element2.RenderTransform = new ScaleTransform(1 - value, 1 - value); + } + else if (TransitionType == TransitionTypeEnum.Spin) + { + double v = value * 100; + v = (v * 360) / 100; + + var group1 = new TransformGroup(); + group1.Children.Add(new RotateTransform(v)); + group1.Children.Add(new ScaleTransform(value, value)); + + var group2 = new TransformGroup(); + group2.Children.Add(new RotateTransform(360 - v)); + group2.Children.Add(new ScaleTransform(1 - value, 1 - value)); + + element1.RenderTransform = group1; + element2.RenderTransform = group2; + } + else if (TransitionType == TransitionTypeEnum.Carousel) + { + double v = value * 100; + v = (v * this.ActualWidth) / 100; + + var group1 = new TransformGroup(); + group1.Children.Add(new ScaleTransform(value, value)); + group1.Children.Add(new TranslateTransform(v - this.ActualWidth, 0)); + + var group2 = new TransformGroup(); + group2.Children.Add(new TranslateTransform(v * 2, 0)); + group2.Children.Add(new ScaleTransform(1 - value, 1 - value)); + + element1.RenderTransform = group1; + element2.RenderTransform = group2; + } + else if (TransitionType == TransitionTypeEnum.Skew) + { + double v = value * 100; + v = (v * 180) / 100; + element2.RenderTransform = new SkewTransform(v, 0); + element1.RenderTransform = new SkewTransform(v - 180, 0); + } + else if (TransitionType == TransitionTypeEnum.Push) + { + element1.RenderTransformOrigin = new Point(1, 0.5); + element2.RenderTransformOrigin = new Point(0, 0.5); + element1.RenderTransform = new ScaleTransform(value, 1); + element2.RenderTransform = new ScaleTransform(1 - value, 1); + } + if (AlwaysFade) + { + element1.Opacity = value; + element2.Opacity = 1 - value; + } + } + + /// <summary> + /// Resets the transformation. + /// </summary> + private void ResetTransformation() + { + foreach (ContentControl control in Controls) + { + control.RenderTransformOrigin = new Point(0.5, 0.5); + } + } + + /// <summary> + /// Execute a transition between the current selected control and the specified content control tag. + /// </summary> + /// <param name="tag">Tag of content control to navigate to.</param> + /// <param name="dataContext">DataContext to assign to the specified content control.</param> + /// <param name="navigationComplete">Navigation completed callback delegate.</param> + public void AutoNavigate(object tag, object dataContext = null, Action navigationComplete = null) + { + if (IsAnimating) + { + return; + } + + ContentControl control = Controls.SingleOrDefault(x => x.Tag != null && x.Tag.ToString() == tag.ToString()); + + if (control == SelectedControl) + { + return; + } + + if (control == null) + { + throw new Exception("Control with tag '" + tag.ToString() + "' not found! (Transition Control)"); + } + + if (dataContext != null) + { + control.DataContext = dataContext; + } + + if (Controls.IndexOf(control) > Controls.IndexOf(fromElement)) + { + navigationCompleteAction = navigationComplete; + toElement = control; + SelectedControl = control; + Next(); + } + else if (Controls.IndexOf(control) < Controls.IndexOf(fromElement)) + { + navigationCompleteAction = navigationComplete; + toElement = control; + SelectedControl = control; + Back(); + } + } + + private void Next() + { + if (IsAnimating) + { + return; + } + + IsAnimating = true; + + if (Controls.IndexOf(toElement) > Controls.IndexOf(fromElement)) + { + element1 = toElement; + element2 = fromElement; + } + else + { + element1 = fromElement; + element2 = toElement; + } + + if (element2 == null) + { + SelectedControl = Controls[0]; + fromElement = SelectedControl; + element2 = fromElement; + } + + freezeAnimation = true; + this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null); + Mix = 0; + freezeAnimation = false; + + DoubleAnimation ani = new DoubleAnimation(1, new Duration(TimeSpan.FromMilliseconds(AnimationTime)), FillBehavior.HoldEnd); + ani.AccelerationRatio = AnimationAcceleration; + ani.DecelerationRatio = AnimationDeceleration; + ani.Completed += ani_NextCompleted; + this.BeginAnimation(MultiTransitionControl.MixProperty, ani); + } + + private void Back() + { + if (IsAnimating) return; + + IsAnimating = true; + + if (Controls.IndexOf(toElement) > Controls.IndexOf(fromElement)) + { + element1 = toElement; + element2 = fromElement; + } + else + { + element1 = fromElement; + element2 = toElement; + } + + freezeAnimation = true; + this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null); + Mix = 1; + freezeAnimation = false; + + DoubleAnimation ani = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(AnimationTime)), FillBehavior.HoldEnd); + ani.Completed += ani_BackCompleted; + ani.AccelerationRatio = AnimationAcceleration; + ani.DecelerationRatio = AnimationDeceleration; + this.BeginAnimation(MultiTransitionControl.MixProperty, ani); + } + + #endregion + + #region Virtuals + + /// <summary> + /// Called when [transition completed]. + /// </summary> + protected virtual void OnTransitionCompleted() + { + if (TransitionComplete != null) TransitionComplete(this); + + if (SelectedControl != null) + { + Panel.SetZIndex(SelectedControl, Controls.Max(x => Panel.GetZIndex(x)) + 1); + } + + if (navigationCompleteAction != null) + { + navigationCompleteAction(); + navigationCompleteAction = null; + } + } + + #endregion + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Controls/TransitionTypeEnum.cs b/Software/Visual Studio/Tango.SharedUI/Controls/TransitionTypeEnum.cs new file mode 100644 index 000000000..1a57c9d56 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Controls/TransitionTypeEnum.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Tango.SharedUI.Controls +{ + /// <summary> + /// Represents a MultiTransitionControl transition style. + /// </summary> + public enum TransitionTypeEnum + { + /// <summary> + /// Generate a cross fade between controls. + /// </summary> + Fade, + /// <summary> + /// Generate slide effect from left to right. + /// </summary> + Slide, + /// <summary> + /// Generate zoom in/out effect. + /// </summary> + Zoom, + /// <summary> + /// Generate twirl effect. + /// </summary> + Spin, + /// <summary> + /// Generate a carousel like slide effect. + /// </summary> + Carousel, + /// <summary> + /// Skew the controls to place. + /// </summary> + Skew, + /// <summary> + /// Generate an effect similar to slide but instead squeeze the controls. + /// </summary> + Push + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/DoubleToIntConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/DoubleToIntConverter.cs new file mode 100644 index 000000000..15ef23292 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/DoubleToIntConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + internal class DoubleToIntConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return System.Convert.ToDouble(value); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return System.Convert.ToInt32(value); + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/EnumToItemsSourceConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/EnumToItemsSourceConverter.cs new file mode 100644 index 000000000..1699647bb --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/EnumToItemsSourceConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + internal class EnumToItemsSourceConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + Type result = value as Type; + return Enum.GetValues(result).Cast<object>().Select(e => new { Value = e, DisplayName = (e as Enum).ToDescription() }); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/IsEnumConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/IsEnumConverter.cs new file mode 100644 index 000000000..3404d3ea4 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/IsEnumConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + internal class IsEnumConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + Type t = value as Type; + return t.IsEnum; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/IsNullConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/IsNullConverter.cs new file mode 100644 index 000000000..7c2b3494d --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/IsNullConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + internal class IsNullConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value == null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/ParameterItemEditorTypeToEditorConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/ParameterItemEditorTypeToEditorConverter.cs new file mode 100644 index 000000000..3022ee07e --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/ParameterItemEditorTypeToEditorConverter.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Core; +using Tango.SharedUI.Editors; + +namespace Tango.SharedUI.Converters +{ + internal class ParameterItemEditorTypeToEditorConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + ParameterItem item = values[0] as ParameterItem; + + if (item != null) + { + Type editorType = Type.GetType(item.CustomEditorTypeName); + + if (editorType != null) + { + IParameterItemEditor editor = Activator.CreateInstance(editorType) as IParameterItemEditor; + editor.ParameterItem = item; + editor.ParameterizedObject = values[1] as IParameterized; + return editor; + } + } + + return null; + } + catch + { + return null; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/StringFormatConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/StringFormatConverter.cs new file mode 100644 index 000000000..19815f903 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Converters/StringFormatConverter.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + internal class StringFormatConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + String stringValue = values[0].ToString(); + String format = values[1] != null ? values[1].ToString() : null; + var resultString = Regex.Match(stringValue, @"^-?[0-9]\d*(\.\d+)?$").Value; + + if (String.IsNullOrWhiteSpace(resultString)) return ""; + + if (resultString == "-") return resultString; + + return System.Convert.ToDouble(resultString).ToString(format != null ? format : ""); + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + String resultString; + + if (value.ToString() == "-" || value.ToString() == ".") + { + resultString = value.ToString() + 0; + } + else + { + resultString = Regex.Match(value.ToString(), @"^-?[0-9]\d*(\.\d+)?$").Value; + } + return new object[] { System.Convert.ToDouble(String.IsNullOrWhiteSpace(resultString) ? "0" : resultString) }; + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/IParameterItemEditor.cs b/Software/Visual Studio/Tango.SharedUI/Editors/IParameterItemEditor.cs new file mode 100644 index 000000000..2cc117bfd --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/IParameterItemEditor.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.SharedUI.Editors +{ + /// <summary> + /// Represents a custom <see cref="ParameterItem"/> editor. + /// </summary> + /// <example> + /// <para class="example-title"> + /// <img class="exampleIcon" src="../Icons/CodeExample.png" /> + /// <i> + /// The following example demonstrates how to implement the IParameterized interface, implement a custom parameter editor and use the ParameterizedEditor to display/edit the object. + /// </i> + /// </para> + /// <para><img class="exampleImage" src="../Media/ParameterizedEditorExample.png" /></para> + /// <i>Implement IParameterized.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/IParameterizedExample.cs" title="Implement IParameterized interface." /> + /// <i>Custom editor.</i> + /// <code lang="XAML" source="../FullAPIExamples/Examples/Core/CustomEditor.xaml" title="Implement custom editor." /> + /// <i>Custom editor code behind.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/CustomEditor.xaml.cs" title="Implement custom editor." /> + /// <i>Use the ParameterizedEditor to display the parameterized object.</i> + /// <code lang="XAML" source="../FullAPIExamples/Examples/Core/ParameterizedEditorExample.xaml" title="Use ParameterizedEditor." /> + /// <i>Code-Behind.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/ParameterizedEditorExample.xaml.cs" title="Use ParameterizedEditor." /> + /// </example> + /// <seealso cref="IParameterized"/> + public interface IParameterItemEditor + { + /// <summary> + /// Gets or sets the parameter item. + /// </summary> + ParameterItem ParameterItem { get; set; } + + /// <summary> + /// Gets or sets the parameterized object. + /// </summary> + IParameterized ParameterizedObject { get; set; } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemEditor.cs b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemEditor.cs new file mode 100644 index 000000000..bb0a321f5 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemEditor.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using Tango.Core; + +namespace Tango.SharedUI.Editors +{ + /// <summary> + /// Represents a <see cref="ParameterItem"/> editor base class. + /// </summary> + public class ParameterItemEditor : UserControl, IParameterItemEditor + { + /// <summary> + /// Gets or sets the parameter item. + /// </summary> + public ParameterItem ParameterItem + { + get { return (ParameterItem)GetValue(ParameterItemProperty); } + set { SetValue(ParameterItemProperty, value); } + } + public static readonly DependencyProperty ParameterItemProperty = + DependencyProperty.Register("ParameterItem", typeof(ParameterItem), typeof(ParameterItemEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the parameterized object. + /// </summary> + public IParameterized ParameterizedObject + { + get { return (IParameterized)GetValue(ParameterizedObjectProperty); } + set { SetValue(ParameterizedObjectProperty, value); } + } + public static readonly DependencyProperty ParameterizedObjectProperty = + DependencyProperty.Register("ParameterizedObject", typeof(IParameterized), typeof(ParameterItemEditor), new PropertyMetadata(null)); + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemEditor"/> class. + /// </summary> + public ParameterItemEditor() + { + DataContext = ParameterItem; + this.Loaded += ParameterItemEditor_Loaded; + } + + /// <summary> + /// Handles the Loaded event of the ParameterItemEditor control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> + private void ParameterItemEditor_Loaded(object sender, RoutedEventArgs e) + { + DataContext = ParameterItem; + } + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml new file mode 100644 index 000000000..57bf3f6ff --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml @@ -0,0 +1,45 @@ +<local:ParameterItemEditor + 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:Tango.SharedUI.Editors" + xmlns:fa="http://schemas.fontawesome.io/icons/" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters" + x:Class="Tango.SharedUI.Editors.ParameterItemNumericUpDownEditor" + mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="150" Background="Transparent" BorderBrush="DimGray" BorderThickness="1"> + + <UserControl.Resources> + <converters:StringFormatConverter x:Key="StringFormatConverter"/> + </UserControl.Resources> + + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="113*"/> + <ColumnDefinition Width="37*" MinWidth="30" /> + </Grid.ColumnDefinitions> + + <Grid Grid.Column="1"> + <Grid.RowDefinitions> + <RowDefinition/> + <RowDefinition/> + </Grid.RowDefinitions> + + <RepeatButton x:Name="btnUp" Style="{x:Null}" Background="#151515" Click="btnUp_Click" Grid.Row="0" Padding="2" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}}"> + <fa:ImageAwesome Icon="ArrowUp" Width="5" Height="5" Foreground="Gainsboro" /> + </RepeatButton> + <RepeatButton x:Name="btnDown" Style="{x:Null}" Background="#151515" Click="btnDown_Click" Grid.Row="1" Padding="2" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}}"> + <fa:ImageAwesome Icon="ArrowDown" Width="5" Height="5" Foreground="Gainsboro" /> + </RepeatButton> + </Grid> + + <Grid> + <TextBox x:Name="txtValue" KeyDown="txtValue_KeyDown" IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}}" VerticalContentAlignment="Center" Background="Transparent" HorizontalContentAlignment="Center" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}}"> + <MultiBinding Converter="{StaticResource StringFormatConverter}" Mode="TwoWay"> + <Binding RelativeSource="{RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}" Path="Value" Mode="TwoWay" /> + <Binding RelativeSource="{RelativeSource AncestorType={x:Type local:ParameterItemNumericUpDownEditor}}" Path="Format"/> + </MultiBinding> + </TextBox> + </Grid> + </Grid> +</local:ParameterItemEditor> diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml.cs b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml.cs new file mode 100644 index 000000000..ddc046127 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterItemNumericUpDownEditor.xaml.cs @@ -0,0 +1,177 @@ +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 Tango.SharedUI; + +namespace Tango.SharedUI.Editors +{ + /// <summary> + /// Represents a simple numeric up down editor. + /// </summary> + public partial class ParameterItemNumericUpDownEditor : ParameterItemEditor + { + #region Constructors + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterItemNumericUpDownEditor"/> class. + /// </summary> + public ParameterItemNumericUpDownEditor() + { + InitializeComponent(); + + this.Loaded += ParameterItemNumericUpDownEditor_Loaded; + } + + #endregion + + #region Properties + + /// <summary> + /// Gets or sets the value. + /// </summary> + public double Value + { + get { return (double)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + public static readonly DependencyProperty ValueProperty = + DependencyProperty.Register("Value", typeof(double), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata(0.0, null, (d, value) => { return (d as ParameterItemNumericUpDownEditor).OnCoerceValue((double)value); })); + + /// <summary> + /// Gets or sets the minimum value. + /// </summary> + public double Minimum + { + get { return (double)GetValue(MinimumProperty); } + set { SetValue(MinimumProperty, value); } + } + public static readonly DependencyProperty MinimumProperty = + DependencyProperty.Register("Minimum", typeof(double), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata(0.0)); + + /// <summary> + /// Gets or sets the maximum value. + /// </summary> + public double Maximum + { + get { return (double)GetValue(MaximumProperty); } + set { SetValue(MaximumProperty, value); } + } + public static readonly DependencyProperty MaximumProperty = + DependencyProperty.Register("Maximum", typeof(double), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata(100.0)); + + /// <summary> + /// Gets or sets the tick frequency for the up/down buttons. + /// </summary> + public double Tick + { + get { return (double)GetValue(TickProperty); } + set { SetValue(TickProperty, value); } + } + public static readonly DependencyProperty TickProperty = + DependencyProperty.Register("Tick", typeof(double), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata(1.0)); + + /// <summary> + /// Gets or sets the value display format. + /// </summary> + public String Format + { + get { return (String)GetValue(FormatProperty); } + set { SetValue(FormatProperty, value); } + } + public static readonly DependencyProperty FormatProperty = + DependencyProperty.Register("Format", typeof(String), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata("0.0")); + + /// <summary> + /// Gets or sets a value indicating whether the value is editable through keyboard. + /// </summary> + public bool IsReadOnly + { + get { return (bool)GetValue(IsReadOnlyProperty); } + set { SetValue(IsReadOnlyProperty, value); } + } + public static readonly DependencyProperty IsReadOnlyProperty = + DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(ParameterItemNumericUpDownEditor), new PropertyMetadata(false)); + + #endregion + + #region Virtual Methods + + /// <summary> + /// Invoked before the value has changed. + /// </summary> + /// <param name="value">The value.</param> + /// <returns></returns> + protected virtual object OnCoerceValue(double value) + { + if (value > Maximum) return Maximum; + if (value < Minimum) return Minimum; + + return value; + } + + #endregion + + #region Event Handlers + + /// <summary> + /// Handles the Click event of the btnUp control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> + private void btnUp_Click(object sender, RoutedEventArgs e) + { + Value += Tick; + } + + /// <summary> + /// Handles the Click event of the btnDown control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> + private void btnDown_Click(object sender, RoutedEventArgs e) + { + Value -= Tick; + } + + /// <summary> + /// Handles the KeyDown event of the txtValue control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="KeyEventArgs"/> instance containing the event data.</param> + private void txtValue_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter || e.Key == Key.Escape) + { + BindingOperations.GetBindingExpressionBase((TextBox)txtValue, TextBox.TextProperty).UpdateSource(); + } + } + + /// <summary> + /// Handles the Loaded event of the ParameterItemNumericUpDownEditor control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param> + private void ParameterItemNumericUpDownEditor_Loaded(object sender, RoutedEventArgs e) + { + if (ParameterItem != null) + { + Minimum = Convert.ToDouble(ParameterItem.Minimum); + Maximum = Convert.ToDouble(ParameterItem.Maximum); + this.Bind(ValueProperty, ParameterItem, Tango.Core.ParameterItem.ValueProperty, BindingMode.TwoWay); + } + } + + #endregion + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml new file mode 100644 index 000000000..d80852b73 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml @@ -0,0 +1,129 @@ +<UserControl x:Class="Tango.SharedUI.Editors.ParameterizedEditor" + 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:Tango.SharedUI.Editors" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters" + xmlns:sys="clr-namespace:System;assembly=mscorlib" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="200"> + + <UserControl.Resources> + <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter"></converters:EnumToItemsSourceConverter> + <converters:IsEnumConverter x:Key="IsEnumConverter"></converters:IsEnumConverter> + <converters:ParameterItemEditorTypeToEditorConverter x:Key="ParameterItemEditorTypeToEditorConverter"></converters:ParameterItemEditorTypeToEditorConverter> + <converters:DoubleToIntConverter x:Key="DoubleToIntConverter"></converters:DoubleToIntConverter> + <converters:IsNullConverter x:Key="IsNullConverter"></converters:IsNullConverter> + </UserControl.Resources> + + <Grid> + <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Background="Transparent"> + <ItemsControl Grid.Row="1" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ParameterizedObject.Parameters}" HorizontalContentAlignment="Stretch"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <ContentControl Content="{Binding}" Padding="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemPadding}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemMargin}" MinHeight="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemMinHeight}"> + <ContentControl.Style> + <Style TargetType="ContentControl"> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <StackPanel> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <TextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </StackPanel> + </DataTemplate> + </Setter.Value> + </Setter> + <Style.Resources> + <DataTemplate x:Key="slide"> + <StackPanel> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <Slider Orientation="Horizontal" HorizontalAlignment="Stretch" Minimum="{Binding Minimum}" Maximum="{Binding Maximum}" Value="{Binding Value}" ToolTip="{Binding Value}"></Slider> + </StackPanel> + </DataTemplate> + <DataTemplate x:Key="slideInteger"> + <StackPanel> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <Slider TickFrequency="1" IsSnapToTickEnabled="True" Orientation="Horizontal" HorizontalAlignment="Stretch" Minimum="{Binding Minimum}" Maximum="{Binding Maximum}" Value="{Binding Value,Converter={StaticResource DoubleToIntConverter}}"></Slider> + </StackPanel> + </DataTemplate> + <DataTemplate x:Key="numUpDown"> + <Grid Margin="0 0 0 4" x:Name="grid"> + <Grid.ColumnDefinitions> + <ColumnDefinition/> + <ColumnDefinition/> + </Grid.ColumnDefinitions> + <TextBlock VerticalAlignment="Center" Grid.Column="0" Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <local:ParameterItemNumericUpDownEditor Grid.Column="1" Minimum="-10000" Maximum="10000" Height="25" Value="{Binding RelativeSource={RelativeSource AncestorType=Grid},Path=DataContext.Value,Mode=TwoWay}"></local:ParameterItemNumericUpDownEditor> + </Grid> + </DataTemplate> + <DataTemplate x:Key="enum"> + <StackPanel Margin="0 0 0 4"> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <ComboBox Foreground="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=Foreground}" ItemsSource="{Binding Type,Converter={StaticResource EnumToItemsSourceConverter},Mode=OneTime}" SelectedValue="{Binding Value}" SelectedValuePath="Value" DisplayMemberPath="DisplayName"></ComboBox> + </StackPanel> + </DataTemplate> + <DataTemplate x:Key="chk"> + <CheckBox Margin="0 5 0 5" IsChecked="{Binding Value}" Foreground="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=Foreground}" Content="{Binding Name}"></CheckBox> + </DataTemplate> + <DataTemplate x:Key="text"> + <StackPanel> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <TextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </StackPanel> + </DataTemplate> + <DataTemplate x:Key="custom"> + <StackPanel> + <TextBlock Text="{Binding Name}" Margin="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=ItemLabelMargin}"></TextBlock> + <ContentPresenter> + <ContentPresenter.Content> + <MultiBinding Converter="{StaticResource ParameterItemEditorTypeToEditorConverter}"> + <Binding Path="DataContext" RelativeSource="{RelativeSource AncestorType=StackPanel}"></Binding> + <Binding Path="ParameterizedObject" RelativeSource="{RelativeSource AncestorType=local:ParameterizedEditor}"></Binding> + </MultiBinding> + </ContentPresenter.Content> + </ContentPresenter> + </StackPanel> + </DataTemplate> + </Style.Resources> + <Style.Triggers> + <DataTrigger Binding="{Binding Type}" Value="{x:Type sys:Double}"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=DoubleTemplate,FallbackValue={StaticResource slide},TargetNullValue={StaticResource slide}}"></Setter> + </DataTrigger> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding Type}" Value="{x:Type sys:Double}"></Condition> + <Condition Binding="{Binding Maximum,Converter={StaticResource IsNullConverter}}" Value="True"></Condition> + <Condition Binding="{Binding Minimum,Converter={StaticResource IsNullConverter}}" Value="True"></Condition> + </MultiDataTrigger.Conditions> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=DoubleUpDownTemplate,FallbackValue={StaticResource numUpDown},TargetNullValue={StaticResource numUpDown}}"></Setter> + </MultiDataTrigger> + <DataTrigger Binding="{Binding Type}" Value="{x:Type sys:Int32}"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=Int32Template,FallbackValue={StaticResource slideInteger},TargetNullValue={StaticResource slideInteger}}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Type}" Value="{x:Type sys:Single}"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=SingleTemplate,FallbackValue={StaticResource slide},TargetNullValue={StaticResource slide}}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Type,Converter={StaticResource IsEnumConverter}}" Value="True"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=EnumTemplate,FallbackValue={StaticResource enum},TargetNullValue={StaticResource enum}}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Type}" Value="{x:Type sys:Boolean}"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=BooleanTemplate,FallbackValue={StaticResource chk},TargetNullValue={StaticResource chk}}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Type}" Value="{x:Type sys:String}"> + <Setter Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource AncestorType=local:ParameterizedEditor},Path=StringTemplate,FallbackValue={StaticResource text},TargetNullValue={StaticResource text}}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding HasCustomEditor}" Value="True"> + <Setter Property="ContentTemplate" Value="{StaticResource custom}"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ContentControl.Style> + </ContentControl> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </ScrollViewer> + </Grid> +</UserControl> diff --git a/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml.cs b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml.cs new file mode 100644 index 000000000..f24cdb9af --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/Editors/ParameterizedEditor.xaml.cs @@ -0,0 +1,242 @@ +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 Tango.Core; +using Tango.SharedUI; + +namespace Tango.SharedUI.Editors +{ + /// <summary> + /// <para><img class="classImage" src="../Media/ParameterizedEditor.png" /></para> + /// Represents a scrollable list of auto generated editable controls for objects which inherits from <see cref="IParameterized"/>. + /// </summary> + /// <remarks> + /// <para> + /// The following types are natively supported for display and edit: + /// </para> + /// <list type="bullet"> + /// <item>Double</item> + /// <item>Single</item> + /// <item>Int32</item> + /// <item>Boolean</item> + /// <item>String</item> + /// <item>Point</item> + /// <item>Enum</item> + /// <item>Color</item> + /// <item>Brush</item> + /// </list> + /// <para> + /// See <see cref="IParameterItemEditor"/> to implement other property types using custom editors. + /// </para> + /// </remarks> + /// <example> + /// <para class="example-title"> + /// <img class="exampleIcon" src="../Icons/CodeExample.png" /> + /// <i> + /// The following example demonstrates how to implement the IParameterized interface, implement a custom parameter editor and use the ParameterizedEditor to display/edit the object. + /// </i> + /// </para> + /// <para><img class="exampleImage" src="../Media/ParameterizedEditorExample.png" /></para> + /// <i>Implement IParameterized.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/IParameterizedExample.cs" title="Implement IParameterized interface." /> + /// <i>Custom editor.</i> + /// <code lang="XAML" source="../FullAPIExamples/Examples/Core/CustomEditor.xaml" title="Implement custom editor." /> + /// <i>Custom editor code behind.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/CustomEditor.xaml.cs" title="Implement custom editor." /> + /// <i>Use the ParameterizedEditor to display the parameterized object.</i> + /// <code lang="XAML" source="../FullAPIExamples/Examples/Core/ParameterizedEditorExample.xaml" title="Use ParameterizedEditor." /> + /// <i>Code-Behind.</i> + /// <code lang="C#" source="../FullAPIExamples/Examples/Core/ParameterizedEditorExample.xaml.cs" title="Use ParameterizedEditor." /> + /// </example> + /// <seealso cref="Tango.SharedUI.HybridControl" /> + public partial class ParameterizedEditor : UserControl + { + /// <summary> + /// Initializes a new instance of the <see cref="ParameterizedEditor"/> class. + /// </summary> + public ParameterizedEditor() + { + InitializeComponent(); + } + + /// <summary> + /// Gets or sets the parameterized object. + /// </summary> + public IParameterized ParameterizedObject + { + get { return (IParameterized)GetValue(ParameterizedObjectProperty); } + set { SetValue(ParameterizedObjectProperty, value); } + } + public static readonly DependencyProperty ParameterizedObjectProperty = + DependencyProperty.Register("ParameterizedObject", typeof(IParameterized), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets a single item padding. + /// </summary> + public Thickness ItemPadding + { + get { return (Thickness)GetValue(ItemPaddingProperty); } + set { SetValue(ItemPaddingProperty, value); } + } + public static readonly DependencyProperty ItemPaddingProperty = + DependencyProperty.Register("ItemPadding", typeof(Thickness), typeof(ParameterizedEditor), new PropertyMetadata(new Thickness())); + + /// <summary> + /// Gets or sets a single item margin. + /// </summary> + public Thickness ItemMargin + { + get { return (Thickness)GetValue(ItemMarginProperty); } + set { SetValue(ItemMarginProperty, value); } + } + public static readonly DependencyProperty ItemMarginProperty = + DependencyProperty.Register("ItemMargin", typeof(Thickness), typeof(ParameterizedEditor), new PropertyMetadata(new Thickness())); + + /// <summary> + /// Gets or sets a single item minimum height. + /// </summary> + public double ItemMinHeight + { + get { return (double)GetValue(ItemMinHeightProperty); } + set { SetValue(ItemMinHeightProperty, value); } + } + public static readonly DependencyProperty ItemMinHeightProperty = + DependencyProperty.Register("ItemMinHeight", typeof(double), typeof(ParameterizedEditor), new PropertyMetadata(0.0)); + + /// <summary> + /// Gets or sets a single item label margin. + /// </summary> + public Thickness ItemLabelMargin + { + get { return (Thickness)GetValue(ItemLabelMarginProperty); } + set { SetValue(ItemLabelMarginProperty, value); } + } + public static readonly DependencyProperty ItemLabelMarginProperty = + DependencyProperty.Register("ItemLabelMargin", typeof(Thickness), typeof(ParameterizedEditor), new PropertyMetadata(new Thickness())); + + #region Templates + + /// <summary> + /// Gets or sets the double template. + /// </summary> + public DataTemplate DoubleTemplate + { + get { return (DataTemplate)GetValue(DoubleTemplateProperty); } + set { SetValue(DoubleTemplateProperty, value); } + } + public static readonly DependencyProperty DoubleTemplateProperty = + DependencyProperty.Register("DoubleTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the int32 template. + /// </summary> + public DataTemplate Int32Template + { + get { return (DataTemplate)GetValue(Int32TemplateProperty); } + set { SetValue(Int32TemplateProperty, value); } + } + public static readonly DependencyProperty Int32TemplateProperty = + DependencyProperty.Register("Int32Template", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the single template. + /// </summary> + public DataTemplate SingleTemplate + { + get { return (DataTemplate)GetValue(SingleTemplateProperty); } + set { SetValue(SingleTemplateProperty, value); } + } + public static readonly DependencyProperty SingleTemplateProperty = + DependencyProperty.Register("SingleTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the double up down template. + /// </summary> + public DataTemplate DoubleUpDownTemplate + { + get { return (DataTemplate)GetValue(DoubleUpDownTemplateProperty); } + set { SetValue(DoubleUpDownTemplateProperty, value); } + } + public static readonly DependencyProperty DoubleUpDownTemplateProperty = + DependencyProperty.Register("DoubleUpDownTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the boolean template. + /// </summary> + public DataTemplate BooleanTemplate + { + get { return (DataTemplate)GetValue(BooleanTemplateProperty); } + set { SetValue(BooleanTemplateProperty, value); } + } + public static readonly DependencyProperty BooleanTemplateProperty = + DependencyProperty.Register("BooleanTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the enum template. + /// </summary> + public DataTemplate EnumTemplate + { + get { return (DataTemplate)GetValue(EnumTemplateProperty); } + set { SetValue(EnumTemplateProperty, value); } + } + public static readonly DependencyProperty EnumTemplateProperty = + DependencyProperty.Register("EnumTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the color template. + /// </summary> + public DataTemplate ColorTemplate + { + get { return (DataTemplate)GetValue(ColorTemplateProperty); } + set { SetValue(ColorTemplateProperty, value); } + } + public static readonly DependencyProperty ColorTemplateProperty = + DependencyProperty.Register("ColorTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the brush template. + /// </summary> + public DataTemplate BrushTemplate + { + get { return (DataTemplate)GetValue(BrushTemplateProperty); } + set { SetValue(BrushTemplateProperty, value); } + } + public static readonly DependencyProperty BrushTemplateProperty = + DependencyProperty.Register("BrushTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the point template. + /// </summary> + public DataTemplate PointTemplate + { + get { return (DataTemplate)GetValue(PointTemplateProperty); } + set { SetValue(PointTemplateProperty, value); } + } + public static readonly DependencyProperty PointTemplateProperty = + DependencyProperty.Register("PointTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the string template. + /// </summary> + public DataTemplate StringTemplate + { + get { return (DataTemplate)GetValue(StringTemplateProperty); } + set { SetValue(StringTemplateProperty, value); } + } + public static readonly DependencyProperty StringTemplateProperty = + DependencyProperty.Register("StringTemplate", typeof(DataTemplate), typeof(ParameterizedEditor), new PropertyMetadata(null)); + + #endregion + } +} diff --git a/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj b/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj index d01e7b2f3..c04c8692a 100644 --- a/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj +++ b/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj @@ -30,6 +30,9 @@ <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> + <Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL"> + <HintPath>..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath> + </Reference> <Reference Include="PresentationCore" /> <Reference Include="PresentationFramework" /> <Reference Include="System" /> @@ -49,14 +52,53 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="Commands\RelayCommand.cs" /> + <Compile Include="Controls\MultiTransitionControl.xaml.cs"> + <DependentUpon>MultiTransitionControl.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\TransitionTypeEnum.cs" /> <Compile Include="Converters\BooleanInverseConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityInverseConverter.cs" /> + <Compile Include="Converters\DoubleToIntConverter.cs" /> <Compile Include="Converters\EnumToDescriptionConverter.cs" /> + <Compile Include="Converters\EnumToItemsSourceConverter.cs" /> + <Compile Include="Converters\IsEnumConverter.cs" /> + <Compile Include="Converters\IsNullConverter.cs" /> <Compile Include="Converters\NullObjectToBooleanConverter.cs" /> + <Compile Include="Converters\ParameterItemEditorTypeToEditorConverter.cs" /> <Compile Include="Converters\PathToShortPathConverter.cs" /> + <Compile Include="Converters\StringFormatConverter.cs" /> + <Compile Include="Editors\IParameterItemEditor.cs" /> + <Compile Include="Editors\ParameterItemEditor.cs" /> + <Compile Include="Editors\ParameterItemNumericUpDownEditor.xaml.cs"> + <DependentUpon>ParameterItemNumericUpDownEditor.xaml</DependentUpon> + </Compile> + <Compile Include="Editors\ParameterizedEditor.xaml.cs"> + <DependentUpon>ParameterizedEditor.xaml</DependentUpon> + </Compile> <Compile Include="ExtendedObject.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Page Include="Controls\MultiTransitionControl.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Editors\ParameterItemNumericUpDownEditor.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Editors\ParameterizedEditor.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.SharedUI/packages.config b/Software/Visual Studio/Tango.SharedUI/packages.config new file mode 100644 index 000000000..86110f9d8 --- /dev/null +++ b/Software/Visual Studio/Tango.SharedUI/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net45" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.Stubs/AvailableStub.cs b/Software/Visual Studio/Tango.Stubs/AvailableStub.cs new file mode 100644 index 000000000..64fbfbe9b --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/AvailableStub.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport; + +namespace Tango.Stubs +{ + public class AvailableStub + { + public Type Type { get; set; } + + public String Name { get; set; } + + public String Description { get; set; } + + public AvailableStub(Type type, String name, String description) + { + Type = type; + Name = name; + Description = description; + } + + public StubBase CreateInstance(ITransporter transporter) + { + return Activator.CreateInstance(Type, transporter) as StubBase; + } + } +} diff --git a/Software/Visual Studio/Tango.Stubs/IStub.cs b/Software/Visual Studio/Tango.Stubs/IStub.cs new file mode 100644 index 000000000..70629ea8f --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/IStub.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.Stubs +{ + public interface IStub : IParameterized + { + StubState State { get; } + Task<String> Run(Action<String> multiResponseCallback); + Task<String> Cancel(); + } +} diff --git a/Software/Visual Studio/Tango.Stubs/Properties/AssemblyInfo.cs b/Software/Visual Studio/Tango.Stubs/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c91630b59 --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Tango - Stubs Collection")] +[assembly: ComVisible(false)]
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.Stubs/StubAttribute.cs b/Software/Visual Studio/Tango.Stubs/StubAttribute.cs new file mode 100644 index 000000000..20fe1dea0 --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/StubAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Stubs +{ + public class StubAttribute : Attribute + { + public String Name { get; set; } + + public String Description { get; set; } + + public StubAttribute(String name, String description) + { + Name = name; + Description = description; + } + } +} diff --git a/Software/Visual Studio/Tango.Stubs/StubBase.cs b/Software/Visual Studio/Tango.Stubs/StubBase.cs new file mode 100644 index 000000000..9270a8702 --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/StubBase.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Logging; +using Tango.SharedUI; +using Tango.Transport; + +namespace Tango.Stubs +{ + public abstract class StubBase : ExtendedObject, IStub + { + [ParameterIgnore] + public ITransporter Transporter { get; set; } + + [ParameterIgnore] + public ReadOnlyObservableCollection<ParameterItem> Parameters { get; set; } + + private StubState _state; + [ParameterIgnore] + public StubState State + { + get { return _state; } + protected set { _state = value; RaisePropertyChanged(nameof(State)); } + } + + + public StubBase(ITransporter transporter) + { + Transporter = transporter; + Parameters = new ReadOnlyObservableCollection<ParameterItem>(this.CreateParametersCollection(ParameterItemMode.Event)); + } + + public virtual Task<String> Cancel() + { + return Task<String>.Factory.StartNew(() => + { + return ""; + }); + } + + public async virtual Task<String> Run(Action<String> multiResponseCallback) + { + String response = String.Empty; + + try + { + LogManager.Log("Executing stub " + this.GetType().Name + "..."); + State = StubState.Running; + response = await OnRun(multiResponseCallback); + State = StubState.Passed; + LogManager.Log("Stub completed successfully."); + } + catch (Exception ex) + { + State = StubState.Failed; + response = LogManager.Log(ex, "Stub failed.").ToString(); + } + + return response; + } + + protected abstract Task<String> OnRun(Action<String> multiResponseCallback); + + public static List<AvailableStub> GetAvailableStubs() + { + List<AvailableStub> results = new List<AvailableStub>(); + + foreach (Type type in Assembly.GetAssembly(typeof(StubBase)).GetTypes().Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(StubBase)))) + { + StubAttribute att = type.GetCustomAttributes(typeof(StubAttribute), true).FirstOrDefault() as StubAttribute; + AvailableStub availableStub = new AvailableStub(type, att.Name, att.Description); + results.Add(availableStub); + } + + return results; + } + } +} diff --git a/Software/Visual Studio/Tango.Stubs/StubState.cs b/Software/Visual Studio/Tango.Stubs/StubState.cs new file mode 100644 index 000000000..1839bc3dc --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/StubState.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Stubs +{ + public enum StubState + { + Stopped, + Running, + Passed, + Failed, + Canceled, + } +} diff --git a/Software/Visual Studio/Tango.Stubs/Stubs/Calculate.cs b/Software/Visual Studio/Tango.Stubs/Stubs/Calculate.cs new file mode 100644 index 000000000..36c353dfd --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/Stubs/Calculate.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Logging; +using Tango.PMR; +using Tango.PMR.Stubs; +using Tango.Transport; + +namespace Tango.Stubs.Stubs +{ + [Stub("Calculate", "Calculate two numbers and return the result.")] + public class Calculate : StubBase + { + public Calculate(ITransporter transporter) : base(transporter) + { + } + + [ParameterItem(Minimum = null, Maximum = null)] + public double NumberA { get; set; } + + [ParameterItem(Minimum = null, Maximum = null)] + public double NumberB { get; set; } + + protected async override Task<string> OnRun(Action<String> multiResponseCallback) + { + var request = MessageFactory.CreateContainer<CalculateRequest>(); + request.Message.A = NumberA; + request.Message.B = NumberB; + var response = await Transporter.SendRequest<CalculateRequest, CalculateResponse>(request); + return response.Sum.ToString(); + } + } +} diff --git a/Software/Visual Studio/Tango.Stubs/Stubs/Progress.cs b/Software/Visual Studio/Tango.Stubs/Stubs/Progress.cs new file mode 100644 index 000000000..323f2b35e --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/Stubs/Progress.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Logging; +using Tango.PMR; +using Tango.PMR.Stubs; +using Tango.Transport; + +namespace Tango.Stubs.Stubs +{ + [Stub("Progress", "Check for multiple response request")] + public class Progress : StubBase + { + public Progress(ITransporter transporter) : base(transporter) + { + } + + protected override Task<string> OnRun(Action<String> multiResponseCallback) + { + Transporter.SendMultiRequest<ProgressRequest, ProgressResponse>(MessageFactory.CreateContainer<ProgressRequest>(), (response) => + { + multiResponseCallback(response.Progress.ToString()); + }); + + return Task.FromResult<String>(""); + } + } +} diff --git a/Software/Visual Studio/Tango.Stubs/Tango.Stubs.csproj b/Software/Visual Studio/Tango.Stubs/Tango.Stubs.csproj new file mode 100644 index 000000000..f4dbf9bb4 --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/Tango.Stubs.csproj @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{1981B537-39E9-4E7D-8430-27466481AEEE}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Tango.Stubs</RootNamespace> + <AssemblyName>Tango.Stubs</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\Build\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL"> + <HintPath>..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="AvailableStub.cs" /> + <Compile Include="IStub.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Stubs\Progress.cs" /> + <Compile Include="Stubs\Calculate.cs" /> + <Compile Include="StubAttribute.cs" /> + <Compile Include="StubBase.cs" /> + <Compile Include="StubState.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Emulations\Tango.Emulations.csproj"> + <Project>{63561e19-ff5a-414b-a5ef-e30711543e1d}</Project> + <Name>Tango.Emulations</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Logging\Tango.Logging.csproj"> + <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project> + <Name>Tango.Logging</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.PMR\Tango.PMR.csproj"> + <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project> + <Name>Tango.PMR</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Protobuf\Tango.Protobuf.csproj"> + <Project>{40073806-914e-4e78-97ab-fa9639308ebe}</Project> + <Name>Tango.Protobuf</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.SharedUI\Tango.SharedUI.csproj"> + <Project>{ac489889-6e50-4f16-9dba-ff4c6f9ec72b}</Project> + <Name>Tango.SharedUI</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Transport\Tango.Transport.csproj"> + <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> + <Name>Tango.Transport</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.Stubs/packages.config b/Software/Visual Studio/Tango.Stubs/packages.config new file mode 100644 index 000000000..e7e6cbade --- /dev/null +++ b/Software/Visual Studio/Tango.Stubs/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net45" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual Studio/Tango.Transport/ITransporter.cs b/Software/Visual Studio/Tango.Transport/ITransporter.cs index 5142b68f1..6699e1f58 100644 --- a/Software/Visual Studio/Tango.Transport/ITransporter.cs +++ b/Software/Visual Studio/Tango.Transport/ITransporter.cs @@ -44,6 +44,28 @@ namespace Tango.Transport Task<Response> SendRequest<Request, Response>(TangoMessage<Request> request, ITransportAdapter adapter) where Request : IMessage<Request> where Response : IMessage<Response>; /// <summary> + /// Sends a request through all adapters which is expected to return multiple response messages. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="adapter">Transport adapter</param> + /// <param name="responseCallback">The response callback delegate.</param> + /// <returns></returns> + void SendMultiRequest<Request, Response>(TangoMessage<Request> request, Action<Response> responseCallback) where Request : IMessage<Request> where Response : IMessage<Response>; + + /// <summary> + /// Sends a request through the specified adapter which is expected to return multiple response messages. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="adapter">Transport adapter</param> + /// <param name="responseCallback">The response callback delegate.</param> + /// <returns></returns> + void SendMultiRequest<Request, Response>(TangoMessage<Request> request, ITransportAdapter adapter,Action<Response> responseCallback) where Request : IMessage<Request> where Response : IMessage<Response>; + + /// <summary> /// Sends a response. /// </summary> /// <typeparam name="Response">The type of the response.</typeparam> diff --git a/Software/Visual Studio/Tango.Transport/TransportMessage.cs b/Software/Visual Studio/Tango.Transport/TransportMessage.cs index e10c736a5..4f864f9f6 100644 --- a/Software/Visual Studio/Tango.Transport/TransportMessage.cs +++ b/Software/Visual Studio/Tango.Transport/TransportMessage.cs @@ -15,6 +15,8 @@ namespace Tango.Transport { private TaskCompletionSource<T> _completionSource; + public Action<T> ResponseCallback { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="TransportMessage{T}"/> class. /// </summary> @@ -45,5 +47,14 @@ namespace Tango.Transport { _completionSource.SetException(ex); } + + /// <summary> + /// Invokes the response callback. + /// </summary> + /// <param name="response">The response.</param> + public override void InvokeResponseCallback(object response) + { + ResponseCallback((T)response); + } } } diff --git a/Software/Visual Studio/Tango.Transport/TransportMessageBase.cs b/Software/Visual Studio/Tango.Transport/TransportMessageBase.cs index c20b11555..d15e17755 100644 --- a/Software/Visual Studio/Tango.Transport/TransportMessageBase.cs +++ b/Software/Visual Studio/Tango.Transport/TransportMessageBase.cs @@ -17,6 +17,11 @@ namespace Tango.Transport public ITransportAdapter Adapter { get; set; } /// <summary> + /// Gets or sets a value indicating whether this instance is multi response. + /// </summary> + public bool IsMultiResponse { get; set; } + + /// <summary> /// Gets or sets the message token. /// </summary> public String Token { get; set; } @@ -49,6 +54,12 @@ namespace Tango.Transport public abstract void SetException(Exception ex); /// <summary> + /// Invokes the response callback. + /// </summary> + /// <param name="response">The response.</param> + public abstract void InvokeResponseCallback(object response); + + /// <summary> /// Initializes a new instance of the <see cref="TransportMessageBase"/> class. /// </summary> /// <param name="token">The token.</param> diff --git a/Software/Visual Studio/Tango.Transport/TransporterBase.cs b/Software/Visual Studio/Tango.Transport/TransporterBase.cs index 073499225..9090bbfa2 100644 --- a/Software/Visual Studio/Tango.Transport/TransporterBase.cs +++ b/Software/Visual Studio/Tango.Transport/TransporterBase.cs @@ -287,6 +287,36 @@ namespace Tango.Transport } /// <summary> + /// Sends a request through all adapters which is expected to return multiple response messages. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="responseCallback">The response callback delegate.</param> + public void SendMultiRequest<Request, Response>(TangoMessage<Request> request, Action<Response> responseCallback) where Request : IMessage<Request> where Response : IMessage<Response> + { + SendMultiRequest(request, null, responseCallback); + } + + /// <summary> + /// Sends a request through the specified adapter which is expected to return multiple response messages. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="adapter">Transport adapter</param> + /// <param name="responseCallback">The response callback delegate.</param> + public void SendMultiRequest<Request, Response>(TangoMessage<Request> request, ITransportAdapter adapter, Action<Response> responseCallback) where Request : IMessage<Request> where Response : IMessage<Response> + { + TransportMessage<Response> message = new TransportMessage<Response>(adapter, request.Container.Token, request, TransportMessageDirection.Request, OnSerializeingMessage(request), null) + { + IsMultiResponse = true, + ResponseCallback = responseCallback, + }; + _sendingQueue.Enqueue(message); + } + + /// <summary> /// Sends a response. /// </summary> /// <typeparam name="Response">The type of the response.</typeparam> @@ -406,15 +436,29 @@ namespace Tango.Transport if (request != null) { - _pendingRequests.Remove(request); - - try + if (!request.IsMultiResponse) { - request.SetResult(OnParseContainer(container)); + _pendingRequests.Remove(request); + + try + { + request.SetResult(OnParseContainer(container)); + } + catch (Exception ex) + { + request.SetException(ex); + } } - catch (Exception ex) + else { - request.SetException(ex); + try + { + request.InvokeResponseCallback(OnParseContainer(container)); + } + catch (Exception ex) + { + throw ex; + } } } else diff --git a/Software/Visual Studio/Tango.sln b/Software/Visual Studio/Tango.sln index dff95ce1a..88b353994 100644 --- a/Software/Visual Studio/Tango.sln +++ b/Software/Visual Studio/Tango.sln @@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.MachineEM.UI", "Utili EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.MobileEM.UI", "Utilities\Tango.MobileEM.UI\Tango.MobileEM.UI.csproj", "{372401B3-FFEB-483F-965F-261506B3FDFB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.Stubs", "Tango.Stubs\Tango.Stubs.csproj", "{1981B537-39E9-4E7D-8430-27466481AEEE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -93,6 +95,10 @@ Global {372401B3-FFEB-483F-965F-261506B3FDFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {372401B3-FFEB-483F-965F-261506B3FDFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {372401B3-FFEB-483F-965F-261506B3FDFB}.Release|Any CPU.Build.0 = Release|Any CPU + {1981B537-39E9-4E7D-8430-27466481AEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1981B537-39E9-4E7D-8430-27466481AEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1981B537-39E9-4E7D-8430-27466481AEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1981B537-39E9-4E7D-8430-27466481AEEE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml index 5aa87af23..83d97bea5 100644 --- a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml @@ -1,6 +1,7 @@ <Application x:Class="Tango.MobileEM.UI.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:vm="clr-namespace:Tango.MobileEM.UI.ViewModels" xmlns:local="clr-namespace:Tango.MobileEM.UI" StartupUri="MainWindow.xaml"> <Application.Resources> @@ -14,6 +15,13 @@ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Red.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatButton.xaml" /> + + <!--View Models--> + <ResourceDictionary> + <vm:MainWindowVM x:Key="MainWindowVM"></vm:MainWindowVM> + <vm:MainViewVM x:Key="MainViewVM"></vm:MainViewVM> + <vm:StubsViewVM x:Key="StubsViewVM"></vm:StubsViewVM> + </ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml.cs index 9819b418d..57e3ddcad 100644 --- a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml.cs +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/App.xaml.cs @@ -5,6 +5,9 @@ using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; +using Tango.Emulations.Emulators; +using Tango.Transport.Adapters; +using Tango.Transport.Transporters; namespace Tango.MobileEM.UI { @@ -13,5 +16,12 @@ namespace Tango.MobileEM.UI /// </summary> public partial class App : Application { + public static MobileEmulator Emulator { get; set; } + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + Emulator = new MobileEmulator(new ProtoTransporter(new TcpTransportAdapter("127.0.0.1", 9999))); + } } } diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml index 7cd7213c5..1280b76f8 100644 --- a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml @@ -5,10 +5,12 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:views="clr-namespace:Tango.MobileEM.UI.Views" xmlns:fa="http://schemas.fontawesome.io/icons/" xmlns:local="clr-namespace:Tango.MobileEM.UI" mc:Ignorable="d" - Title="Tango Machine Emulator" Height="558" Width="354" TitleCaps="False" BorderBrush="Gray" BorderThickness="1" WindowStartupLocation="CenterScreen" Background="#202020" Foreground="Gainsboro" DataContext="{Binding RelativeSource={RelativeSource Self}}"> + Title="Tango Machine Emulator" Height="668" Width="416" TitleCaps="False" BorderBrush="Gray" BorderThickness="1" WindowStartupLocation="CenterScreen" Background="#202020" Foreground="Gainsboro" DataContext="{StaticResource MainWindowVM}"> <Grid> <Grid> <Image Source="Images/phone.png" RenderOptions.BitmapScalingMode="Fant" Stretch="Fill"></Image> @@ -31,24 +33,47 @@ <RowDefinition Height="40"/> </Grid.RowDefinitions> - <Grid> - <Button Width="100" Height="50" Click="Button_Click">SEND</Button> - </Grid> + <controls:MultiTransitionControl x:Name="TransitionControl" AlwaysFade="True" TransitionType="Zoom" AnimationTime="500"> + <controls:MultiTransitionControl.Controls> + <ContentControl Tag="MainView"> + <views:MainView DataContext="{StaticResource MainViewVM}"></views:MainView> + </ContentControl> + <ContentControl Tag="StubsView"> + <views:StubsView DataContext="{StaticResource StubsViewVM}"></views:StubsView> + </ContentControl> + <ContentControl Tag="StubView"> + <views:StubView></views:StubView> + </ContentControl> + </controls:MultiTransitionControl.Controls> + </controls:MultiTransitionControl> - <UniformGrid Grid.Row="1" Columns="2" Background="#151515"> - <Button Margin="5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding Emulator.StopCommand}"> - <StackPanel Orientation="Horizontal"> - <fa:ImageAwesome Icon="Unlink" Width="16"></fa:ImageAwesome> - <TextBlock VerticalAlignment="Center" Margin="5 0 10 0">Disconnect</TextBlock> - </StackPanel> - </Button> - <Button Margin="5 5 0 5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding Emulator.StartCommand}"> + <Grid Grid.Row="1" Background="#151515"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="40"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + + <Button Margin="5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding BackCommand}"> <StackPanel Orientation="Horizontal"> - <fa:ImageAwesome Icon="Link" Width="16"></fa:ImageAwesome> - <TextBlock VerticalAlignment="Center" Margin="5 0 10 0">Connect</TextBlock> + <fa:ImageAwesome Icon="ArrowLeft" Width="16"></fa:ImageAwesome> </StackPanel> </Button> - </UniformGrid> + + <UniformGrid Columns="2" Grid.Column="1"> + <Button Margin="5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding Emulator.StopCommand}"> + <StackPanel Orientation="Horizontal"> + <fa:ImageAwesome Icon="Unlink" Width="16"></fa:ImageAwesome> + <TextBlock VerticalAlignment="Center" Margin="5 0 10 0">Disconnect</TextBlock> + </StackPanel> + </Button> + <Button Margin="5 5 0 5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding Emulator.StartCommand}"> + <StackPanel Orientation="Horizontal"> + <fa:ImageAwesome Icon="Link" Width="16"></fa:ImageAwesome> + <TextBlock VerticalAlignment="Center" Margin="5 0 10 0">Connect</TextBlock> + </StackPanel> + </Button> + </UniformGrid> + </Grid> </Grid> </Grid> </Grid> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml.cs index 72e8a480f..f003f708f 100644 --- a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml.cs +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/MainWindow.xaml.cs @@ -26,29 +26,23 @@ namespace Tango.MobileEM.UI /// </summary> public partial class MainWindow : MetroWindow { - #region Properties - - public MobileEmulator Emulator - { - get { return (MobileEmulator)GetValue(EmulatorProperty); } - set { SetValue(EmulatorProperty, value); } - } - public static readonly DependencyProperty EmulatorProperty = - DependencyProperty.Register("Emulator", typeof(MobileEmulator), typeof(MainWindow), new PropertyMetadata(null)); - - #endregion + public static MainWindow Instance { get; private set; } public MainWindow() { LogManager.RegisterLogger(new VSOutputLogger()); - - Emulator = new MobileEmulator(new ProtoTransporter(new TcpTransportAdapter("127.0.0.1", 9999))); InitializeComponent(); + Instance = this; } - private void Button_Click(object sender, RoutedEventArgs e) + public static void NavigateTo(Type view) { + Instance.TransitionControl.AutoNavigate(view.Name); + } + public static void NavigateTo(Type view, object context) + { + Instance.TransitionControl.AutoNavigate(view.Name, context); } } } diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Tango.MobileEM.UI.csproj b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Tango.MobileEM.UI.csproj index e376ad738..9546deaed 100644 --- a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Tango.MobileEM.UI.csproj +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Tango.MobileEM.UI.csproj @@ -66,6 +66,19 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </ApplicationDefinition> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="ViewModels\MainWindowVM.cs" /> + <Compile Include="ViewModels\StubsViewVM.cs" /> + <Compile Include="ViewModels\StubViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\StubsView.xaml.cs"> + <DependentUpon>StubsView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\StubView.xaml.cs"> + <DependentUpon>StubView.xaml</DependentUpon> + </Compile> <Page Include="MainWindow.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> @@ -78,6 +91,18 @@ <DependentUpon>MainWindow.xaml</DependentUpon> <SubType>Code</SubType> </Compile> + <Page Include="Views\MainView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\StubsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\StubView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> </ItemGroup> <ItemGroup> <Compile Include="Properties\AssemblyInfo.cs"> @@ -135,6 +160,10 @@ <Project>{ac489889-6e50-4f16-9dba-ff4c6f9ec72b}</Project> <Name>Tango.SharedUI</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.Stubs\Tango.Stubs.csproj"> + <Project>{1981b537-39e9-4e7d-8430-27466481aeee}</Project> + <Name>Tango.Stubs</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.Transport\Tango.Transport.csproj"> <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> <Name>Tango.Transport</Name> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainViewVM.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..fdb751422 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainViewVM.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.MobileEM.UI.Views; +using Tango.SharedUI; +using Tango.SharedUI.Commands; + +namespace Tango.MobileEM.UI.ViewModels +{ + public class MainViewVM : ExtendedObject + { + #region Commands + + public RelayCommand StubsCommand { get; set; } + + #endregion + + public MainViewVM() + { + StubsCommand = new RelayCommand(NavigateToStubs); + } + + private void NavigateToStubs() + { + MainWindow.NavigateTo(typeof(StubsView)); + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainWindowVM.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainWindowVM.cs new file mode 100644 index 000000000..cd5c9bf93 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/MainWindowVM.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Emulations.Emulators; +using Tango.MobileEM.UI.Views; +using Tango.SharedUI; +using Tango.SharedUI.Commands; +using Tango.Transport.Adapters; +using Tango.Transport.Transporters; + +namespace Tango.MobileEM.UI.ViewModels +{ + public class MainWindowVM : ExtendedObject + { + /// <summary> + /// Gets or sets the mobile emulator. + /// </summary> + public MobileEmulator Emulator + { + get { return App.Emulator; } + } + + public RelayCommand BackCommand { get; set; } + + + /// <summary> + /// Initializes a new instance of the <see cref="MainWindowVM"/> class. + /// </summary> + public MainWindowVM() + { + BackCommand = new RelayCommand(Back); + } + + private void Back() + { + MainWindow.NavigateTo(typeof(MainView)); + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubViewVM.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubViewVM.cs new file mode 100644 index 000000000..645df6a13 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubViewVM.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Documents; +using Tango.Logging; +using Tango.SharedUI; +using Tango.SharedUI.Commands; +using Tango.Stubs; + +namespace Tango.MobileEM.UI.ViewModels +{ + public class StubViewVM : ExtendedObject + { + private bool _running; + + public RelayCommand RunCommand { get; set; } + public RelayCommand CancelCommand { get; set; } + public RelayCommand ClearCommand { get; set; } + public StubBase Stub { get; set; } + public AvailableStub AvailableStub { get; set; } + + private String _response; + + public String Response + { + get { return _response; } + set { _response = value; RaisePropertyChanged(nameof(Response)); } + } + + + public StubViewVM(AvailableStub availableStub, StubBase stub) + { + AvailableStub = availableStub; + Stub = stub; + RunCommand = new RelayCommand(Run,(x) => !_running); + CancelCommand = new RelayCommand(Cancel,(x) => _running); + ClearCommand = new RelayCommand(() => Response = String.Empty); + } + + private async void Run() + { + _running = true; + InvalidateRelayCommands(); + Response += await Stub.Run((response) => + { + _running = false; + Response += response + Environment.NewLine; + InvalidateRelayCommands(); + + }) + Environment.NewLine; + + _running = false; + InvalidateRelayCommands(); + } + + private async void Cancel() + { + + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubsViewVM.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubsViewVM.cs new file mode 100644 index 000000000..480ba1c7c --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/ViewModels/StubsViewVM.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.MobileEM.UI.Views; +using Tango.SharedUI; +using Tango.Stubs; + +namespace Tango.MobileEM.UI.ViewModels +{ + public class StubsViewVM : ExtendedObject + { + public List<AvailableStub> AvailableStubs { get; set; } + private AvailableStub _selectedStub; + + public AvailableStub SelectedStub + { + get { return _selectedStub; } + set + { + _selectedStub = value; RaisePropertyChanged(nameof(SelectedStub)); + OnStubSelected(value); + } + } + + + public StubsViewVM() + { + AvailableStubs = StubBase.GetAvailableStubs(); + } + + private void OnStubSelected(AvailableStub availableStub) + { + if (availableStub != null) + { + StubBase stub = availableStub.CreateInstance(App.Emulator.Transporter); + MainWindow.NavigateTo(typeof(StubView), new StubViewVM(availableStub, stub)); + } + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml new file mode 100644 index 000000000..3c8caa918 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml @@ -0,0 +1,29 @@ +<UserControl x:Class="Tango.MobileEM.UI.Views.MainView" + 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:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:fa="http://schemas.fontawesome.io/icons/" + xmlns:local="clr-namespace:Tango.MobileEM.UI.Views" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="200"> + + <Grid Margin="20"> + <UniformGrid Rows="2"> + <Button Width="100" Height="100" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding StubsCommand}"> + <StackPanel Orientation="Vertical"> + <fa:ImageAwesome Icon="Cogs" Width="32"></fa:ImageAwesome> + <TextBlock VerticalAlignment="Center" Margin="10">Stubs</TextBlock> + </StackPanel> + </Button> + + <Button Width="100" Height="100" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding MonitoringCommand}"> + <StackPanel Orientation="Vertical"> + <fa:ImageAwesome Icon="Gratipay" Width="32"></fa:ImageAwesome> + <TextBlock VerticalAlignment="Center" Margin="10">Monitoring</TextBlock> + </StackPanel> + </Button> + </UniformGrid> + </Grid> +</UserControl> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml.cs new file mode 100644 index 000000000..c33fb0fe1 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/MainView.xaml.cs @@ -0,0 +1,29 @@ +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 Tango.SharedUI.Commands; + +namespace Tango.MobileEM.UI.Views +{ + /// <summary> + /// Interaction logic for MainView.xaml + /// </summary> + public partial class MainView : UserControl + { + public MainView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml new file mode 100644 index 000000000..c0fa65b91 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml @@ -0,0 +1,73 @@ +<UserControl x:Class="Tango.MobileEM.UI.Views.StubView" + 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:fa="http://schemas.fontawesome.io/icons/" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:editors="clr-namespace:Tango.SharedUI.Editors;assembly=Tango.SharedUI" + xmlns:local="clr-namespace:Tango.MobileEM.UI.Views" + mc:Ignorable="d" + d:DesignHeight="400" d:DesignWidth="300"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="50"/> + <RowDefinition Height="105*"/> + <RowDefinition Height="68*"/> + </Grid.RowDefinitions> + <Grid VerticalAlignment="Top" Background="#151515"> + <StackPanel Orientation="Horizontal" Margin="5"> + <fa:ImageAwesome Icon="Cogs" Foreground="Red" Width="24" Height="24" VerticalAlignment="Center"></fa:ImageAwesome> + <StackPanel Margin="5 0 0 0" VerticalAlignment="Center"> + <TextBlock Margin="2" FontSize="14" Text="{Binding AvailableStub.Name}"></TextBlock> + <TextBlock Margin="2" FontSize="12" Text="{Binding AvailableStub.Description}"></TextBlock> + </StackPanel> + </StackPanel> + </Grid> + + <Grid Grid.Row="1" Background="#202020"> + <editors:ParameterizedEditor ParameterizedObject="{Binding Stub}" Margin="10" ItemMargin="10" ItemLabelMargin="0 0 0 5" /> + </Grid> + + <Grid Grid.Row="2"> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="40"/> + </Grid.RowDefinitions> + + <Grid Background="Black"> + <Grid.RowDefinitions> + <RowDefinition Height="20"/> + <RowDefinition Height="40*"/> + </Grid.RowDefinitions> + + <TextBlock Background="#151515" Foreground="Red" VerticalAlignment="Center" FontSize="11" Margin="5 0 0 0">Response</TextBlock> + + <TextBox x:Name="txtResponse" TextChanged="txtResponse_TextChanged" Grid.Row="1" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" Background="Transparent" Foreground="Gainsboro" FontSize="10" BorderThickness="0" IsReadOnly="True" Padding="5" Text="{Binding Response}"> + + </TextBox> + </Grid> + + <Grid Grid.Row="1" Background="Black"> + <Rectangle VerticalAlignment="Top" Stroke="#202020" StrokeThickness="1"></Rectangle> + <UniformGrid Columns="3" HorizontalAlignment="Right"> + <Button Cursor="Hand" Width="35" Height="35" Style="{DynamicResource MetroCircleButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding ClearCommand}"> + <StackPanel Orientation="Horizontal"> + <fa:ImageAwesome Icon="Refresh" Foreground="Gainsboro" Width="16"></fa:ImageAwesome> + </StackPanel> + </Button> + <Button Cursor="Hand" Width="35" Height="35" VerticalAlignment="Center" Style="{DynamicResource MetroCircleButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding CancelCommand}"> + <StackPanel Orientation="Horizontal"> + <fa:ImageAwesome Icon="Stop" Foreground="Red" Width="16"></fa:ImageAwesome> + </StackPanel> + </Button> + <Button Cursor="Hand" Width="35" Height="35" VerticalAlignment="Center" Style="{DynamicResource MetroCircleButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding RunCommand}"> + <StackPanel Orientation="Horizontal"> + <fa:ImageAwesome Icon="Play" Width="16" Foreground="LimeGreen"></fa:ImageAwesome> + </StackPanel> + </Button> + </UniformGrid> + </Grid> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml.cs new file mode 100644 index 000000000..8ce034020 --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubView.xaml.cs @@ -0,0 +1,33 @@ +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; + +namespace Tango.MobileEM.UI.Views +{ + /// <summary> + /// Interaction logic for StubView.xaml + /// </summary> + public partial class StubView : UserControl + { + public StubView() + { + InitializeComponent(); + } + + private void txtResponse_TextChanged(object sender, TextChangedEventArgs e) + { + txtResponse.ScrollToEnd(); + } + } +} diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml new file mode 100644 index 000000000..effbd48fe --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml @@ -0,0 +1,28 @@ +<UserControl x:Class="Tango.MobileEM.UI.Views.StubsView" + 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:fa="http://schemas.fontawesome.io/icons/" + xmlns:local="clr-namespace:Tango.MobileEM.UI.Views" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="200"> + <Grid> + <ListBox x:Name="list" Background="Transparent" ItemsSource="{Binding AvailableStubs}" SelectedItem="{Binding SelectedStub}" SelectedIndex="-1" SelectionChanged="ListBox_SelectionChanged"> + <ListBox.ItemTemplate> + <DataTemplate> + <Grid> + <StackPanel Orientation="Horizontal" Margin="2 10 0 10"> + <fa:ImageAwesome Icon="Cogs" Foreground="Red" Width="24" Height="24" VerticalAlignment="Center"></fa:ImageAwesome> + <StackPanel Margin="5 0 0 0" VerticalAlignment="Center"> + <TextBlock Margin="2" FontSize="14" Text="{Binding Name}"></TextBlock> + <TextBlock Margin="2" FontSize="12" Text="{Binding Description}"></TextBlock> + </StackPanel> + </StackPanel> + <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="1"></Rectangle> + </Grid> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + </Grid> +</UserControl> diff --git a/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml.cs b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml.cs new file mode 100644 index 000000000..7c42ba82c --- /dev/null +++ b/Software/Visual Studio/Utilities/Tango.MobileEM.UI/Views/StubsView.xaml.cs @@ -0,0 +1,36 @@ +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; + +namespace Tango.MobileEM.UI.Views +{ + /// <summary> + /// Interaction logic for StubsView.xaml + /// </summary> + public partial class StubsView : UserControl + { + public StubsView() + { + InitializeComponent(); + } + + private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (e.AddedItems.Count > 0) + { + list.SelectedIndex = -1; + } + } + } +} |
