diff options
| author | Shlomo Hecht <shlomo@twine-s.com> | 2020-05-18 17:26:52 +0300 |
|---|---|---|
| committer | Shlomo Hecht <shlomo@twine-s.com> | 2020-05-18 17:26:52 +0300 |
| commit | 231591bb23fc74ffd038c2d58af1c8669e6cf61b (patch) | |
| tree | bb8a52ba8dd482699b560d595eacd52bc69755b5 | |
| parent | 049be36c736eb88d9030c2ce720863375ce134cc (diff) | |
| parent | 9b9121935fbf6fc46a346beac95604086961ddde (diff) | |
| download | Tango-231591bb23fc74ffd038c2d58af1c8669e6cf61b.tar.gz Tango-231591bb23fc74ffd038c2d58af1c8669e6cf61b.zip | |
Merge branch 'master' of https://twinetfs.visualstudio.com/Tango/_git/Tango
107 files changed, 6264 insertions, 504 deletions
diff --git a/Software/DB/Tango.mdf b/Software/DB/Tango.mdf Binary files differindex 90ddc4c39..3b670d23b 100644 --- a/Software/DB/Tango.mdf +++ b/Software/DB/Tango.mdf diff --git a/Software/DB/Tango_log.ldf b/Software/DB/Tango_log.ldf Binary files differindex 13bba78e4..811397251 100644 --- a/Software/DB/Tango_log.ldf +++ b/Software/DB/Tango_log.ldf diff --git a/Software/Visual_Studio/Advanced Installer Projects/PPC Installer-cache/cacheIndex.txt b/Software/Visual_Studio/Advanced Installer Projects/PPC Installer-cache/cacheIndex.txt Binary files differindex a603ff06b..9453b5c13 100644 --- a/Software/Visual_Studio/Advanced Installer Projects/PPC Installer-cache/cacheIndex.txt +++ b/Software/Visual_Studio/Advanced Installer Projects/PPC Installer-cache/cacheIndex.txt diff --git a/Software/Visual_Studio/Advanced Installer Projects/PPC Installer.aip b/Software/Visual_Studio/Advanced Installer Projects/PPC Installer.aip index 1cd0ba200..2da259bc0 100644 --- a/Software/Visual_Studio/Advanced Installer Projects/PPC Installer.aip +++ b/Software/Visual_Studio/Advanced Installer Projects/PPC Installer.aip @@ -18,10 +18,10 @@ <ROW Property="ARPNOREPAIR" Value="1" MultiBuildValue="DefaultBuild:1"/> <ROW Property="ARPSYSTEMCOMPONENT" Value="1"/> <ROW Property="Manufacturer" Value="Twine"/> - <ROW Property="ProductCode" Value="1033:{61DA9B2E-261E-4CE4-94D8-1E04EF41CA9E} " Type="16"/> + <ROW Property="ProductCode" Value="1033:{E9D4AC4F-64FC-4C07-81BE-981370DA12AA} " Type="16"/> <ROW Property="ProductLanguage" Value="1033"/> <ROW Property="ProductName" Value="Tango"/> - <ROW Property="ProductVersion" Value="1.1.15.0" Type="32"/> + <ROW Property="ProductVersion" Value="1.1.16.0" Type="32"/> <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/> <ROW Property="UpgradeCode" Value="{F8EAB8B4-FD57-45B7-8307-D52DF760273D}"/> <ROW Property="WindowsType9X" MultiBuildValue="DefaultBuild:Windows 9x/ME" ValueLocId="-"/> @@ -202,13 +202,11 @@ <ROW Component="mscoree.dll" ComponentId="{85F439D0-8FD0-4B99-888D-336C7A125E3D}" Directory_="APPDIR" Attributes="0" KeyPath="mscoree.dll"/> <ROW Component="msvcp140d.dll" ComponentId="{69E32675-9ACF-4C23-A495-300B78913B66}" Directory_="APPDIR" Attributes="0" KeyPath="msvcp140d.dll"/> <ROW Component="protobufnet.dll" ComponentId="{163F1E17-6462-4ABE-BC86-E055F7690139}" Directory_="APPDIR" Attributes="0" KeyPath="protobufnet.dll"/> - <ROW Component="turbojpeg.dll" ComponentId="{C21C2FF4-FF27-4413-B12A-18D5859E5755}" Directory_="win7x64_Dir" Attributes="256" KeyPath="turbojpeg.dll"/> - <ROW Component="turbojpeg.dll.meta" ComponentId="{A5E705A1-3D68-46A7-B45E-A227A8B3ABD4}" Directory_="win7x64_Dir" Attributes="0" KeyPath="turbojpeg.dll.meta" Type="0"/> - <ROW Component="turbojpeg.dll.meta_1" ComponentId="{BD0788A1-1F83-4DD8-819F-943713292B13}" Directory_="win7x86_Dir" Attributes="0" KeyPath="turbojpeg.dll.meta_1" Type="0"/> - <ROW Component="turbojpeg.dll_1" ComponentId="{7376D903-B1F4-4AD4-9027-73C947C73E64}" Directory_="win7x86_Dir" Attributes="0" KeyPath="turbojpeg.dll_1"/> <ROW Component="ucrtbased.dll" ComponentId="{B8D025EA-CD16-4EE7-A3E7-713E2BE82BF3}" Directory_="APPDIR" Attributes="0" KeyPath="ucrtbased.dll"/> <ROW Component="vcruntime140.dll" ComponentId="{144594CC-D19B-45E4-A420-7A1BBB122EE3}" Directory_="APPDIR" Attributes="0" KeyPath="vcruntime140.dll"/> <ROW Component="vcruntime140d.dll" ComponentId="{7653420C-C6C3-4F31-97E8-D6DE417D3DF2}" Directory_="APPDIR" Attributes="0" KeyPath="vcruntime140d.dll"/> + <ROW Component="win7x64" ComponentId="{9D2172C7-152D-40CA-B098-C44ABA5AB1FB}" Directory_="win7x64_Dir" Attributes="0"/> + <ROW Component="win7x86" ComponentId="{BC564E77-CFC8-4588-A532-BBED1668761D}" Directory_="win7x86_Dir" Attributes="0"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent"> <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0"/> @@ -455,10 +453,6 @@ <ROW File="LiteDB.dll" Component_="LiteDB.dll" FileName="LiteDB.dll" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\LiteDB.dll" SelfReg="false"/> <ROW File="Tango.PPC.Shared.dll" Component_="Tango.PPC.Shared.dll" FileName="TANGO~13.DLL|Tango.PPC.Shared.dll" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\Tango.PPC.Shared.dll" SelfReg="false"/> <ROW File="Tango.PPC.Shared.pdb" Component_="Tango.PPC.Shared.dll" FileName="TANGO~17.PDB|Tango.PPC.Shared.pdb" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\Tango.PPC.Shared.pdb" SelfReg="false"/> - <ROW File="turbojpeg.dll" Component_="turbojpeg.dll" FileName="TURBOJ~1.DLL|turbojpeg.dll" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\win7-x64\turbojpeg.dll" SelfReg="false"/> - <ROW File="turbojpeg.dll.meta" Component_="turbojpeg.dll.meta" FileName="TURBOJ~1.MET|turbojpeg.dll.meta" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\win7-x64\turbojpeg.dll.meta" SelfReg="false"/> - <ROW File="turbojpeg.dll_1" Component_="turbojpeg.dll_1" FileName="TURBOJ~1.DLL|turbojpeg.dll" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\win7-x86\turbojpeg.dll" SelfReg="false"/> - <ROW File="turbojpeg.dll.meta_1" Component_="turbojpeg.dll.meta_1" FileName="TURBOJ~1.MET|turbojpeg.dll.meta" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\Build\PPC\Release\win7-x86\turbojpeg.dll.meta" SelfReg="false"/> <ATTRIBUTE name="DontAddFileAttributes" value="true"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.BootstrOptComponent"> @@ -468,7 +462,7 @@ <ROW Action="AI_DetectSoftware" Sequence="101"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent"> - <ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" PackageFolder="..\Build\Installers\PPC" PackageFileName="PPC Installer v1.0.3" Languages="en" InstallationType="4" CabsLocation="1" PackageType="1" FilesInsideExe="true" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install" ExtUI="true" UseLargeSchema="true" ExeName="PPC Installer_v1.1.15"/> + <ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" PackageFolder="..\Build\Installers\PPC" PackageFileName="PPC Installer v1.0.3" Languages="en" InstallationType="4" CabsLocation="1" PackageType="1" FilesInsideExe="true" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install" ExtUI="true" UseLargeSchema="true" ExeName="PPC Installer_v1.1.16"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent"> <ROW Path="<AI_DICTS>ui.ail"/> @@ -536,6 +530,8 @@ <COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent"> <ROW Directory_="SHORTCUTDIR" Component_="SHORTCUTDIR" ManualDelete="false"/> <ROW Directory_="APPDIR" Component_="APPDIR" ManualDelete="true"/> + <ROW Directory_="win7x64_Dir" Component_="win7x64" ManualDelete="false"/> + <ROW Directory_="win7x86_Dir" Component_="win7x86" ManualDelete="false"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent"> <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH_ORIGINAL" Target="[AI_SETUPEXEPATH]"/> @@ -726,10 +722,8 @@ <ROW Feature_="MainFeature" Component_="WebRtc.NET.dll"/> <ROW Feature_="MainFeature" Component_="LiteDB.dll"/> <ROW Feature_="MainFeature" Component_="Tango.PPC.Shared.dll"/> - <ROW Feature_="MainFeature" Component_="turbojpeg.dll"/> - <ROW Feature_="MainFeature" Component_="turbojpeg.dll.meta"/> - <ROW Feature_="MainFeature" Component_="turbojpeg.dll_1"/> - <ROW Feature_="MainFeature" Component_="turbojpeg.dll.meta_1"/> + <ROW Feature_="MainFeature" Component_="win7x86"/> + <ROW Feature_="MainFeature" Component_="win7x64"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent"> <ROW Action="AI_STORE_LOCATION" Condition="(Not Installed) OR REINSTALL" Sequence="1502"/> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs index 45b6d9a36..bb647c6f6 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -11,23 +12,23 @@ namespace Tango.FSE.Diagnostics.Controls { public class DiagnosticsGrid : Grid { - public List<DiagnosticsProjectTabColumnDefinition> Columns + public ObservableCollection<DiagnosticsProjectTabColumnDefinition> Columns { - get { return (List<DiagnosticsProjectTabColumnDefinition>)GetValue(ColumnsProperty); } + get { return (ObservableCollection<DiagnosticsProjectTabColumnDefinition>)GetValue(ColumnsProperty); } set { SetValue(ColumnsProperty, value); } } public static readonly DependencyProperty ColumnsProperty = - DependencyProperty.Register("Columns", typeof(List<DiagnosticsProjectTabColumnDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); + DependencyProperty.Register("Columns", typeof(ObservableCollection<DiagnosticsProjectTabColumnDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); - public List<DiagnosticsProjectTabRowDefinition> Rows + public ObservableCollection<DiagnosticsProjectTabRowDefinition> Rows { - get { return (List<DiagnosticsProjectTabRowDefinition>)GetValue(RowsProperty); } + get { return (ObservableCollection<DiagnosticsProjectTabRowDefinition>)GetValue(RowsProperty); } set { SetValue(RowsProperty, value); } } public static readonly DependencyProperty RowsProperty = - DependencyProperty.Register("Rows", typeof(List<DiagnosticsProjectTabRowDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); + DependencyProperty.Register("Rows", typeof(ObservableCollection<DiagnosticsProjectTabRowDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); - private void LoadDefinitions() + protected virtual void LoadDefinitions() { if (Rows != null && Columns != null) { @@ -36,14 +37,33 @@ namespace Tango.FSE.Diagnostics.Controls foreach (var column in Columns) { - ColumnDefinitions.Add(new ColumnDefinition() { Width = column.Width }); + var columnDefinition = new ColumnDefinition() { Width = column.Width }; + columnDefinition.Bind(ColumnDefinition.WidthProperty, column, nameof(DiagnosticsProjectTabColumnDefinition.Width), System.Windows.Data.BindingMode.TwoWay); + ColumnDefinitions.Add(columnDefinition); } foreach (var row in Rows) { - RowDefinitions.Add(new RowDefinition() { Height = row.Height }); + var rowDefinition = new RowDefinition() { Height = row.Height }; + rowDefinition.Bind(RowDefinition.HeightProperty, row, nameof(DiagnosticsProjectTabRowDefinition.Height), System.Windows.Data.BindingMode.TwoWay); + RowDefinitions.Add(rowDefinition); } + + Columns.CollectionChanged -= Columns_CollectionChanged; + Rows.CollectionChanged -= Rows_CollectionChanged; + Columns.CollectionChanged += Columns_CollectionChanged; + Rows.CollectionChanged += Rows_CollectionChanged; } } + + private void Rows_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + LoadDefinitions(); + } + + private void Columns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + LoadDefinitions(); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml new file mode 100644 index 000000000..2ae7bbeca --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml @@ -0,0 +1,108 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Controls.DiagnosticsGridLinesEditor" + 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:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Controls" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800" x:Name="control" Foreground="#20FFFFFF"> + <Grid> + + <Rectangle HorizontalAlignment="Left" Stroke="{Binding ElementName=control,Path=Foreground}" /> + + <ItemsControl ItemsSource="{Binding ElementName=control,Path=VerticalLineEditors}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <local:DiagnosticsGrid Loaded="Columns_DiagnosticsGrid_Loaded" Columns="{Binding ElementName=control,Path=Columns}" Rows="{Binding ElementName=control,Path=RowsZero}" /> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Grid.Column" Value="{Binding Position}"></Setter> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border> + <Grid HorizontalAlignment="Right"> + <Grid Margin="0 -14 -5 0"> + <Thumb Width="10" Background="Transparent" Cursor="SizeWE" VerticalAlignment="Top" DragDelta="Vertical_Thumb_DragDelta"> + + </Thumb> + + <material:PackIcon Foreground="{StaticResource FSE_PrimaryForegroundBrush}" RenderTransformOrigin="0.5,0.5" Kind="Triangle" IsHitTestVisible="False" Width="12" Height="12"> + <material:PackIcon.RenderTransform> + <RotateTransform Angle="180" /> + </material:PackIcon.RenderTransform> + </material:PackIcon> + </Grid> + <Rectangle Opacity="0.6" StrokeThickness="2" IsHitTestVisible="False" Stroke="{Binding ElementName=control,Path=Foreground}" HorizontalAlignment="Right"></Rectangle> + </Grid> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + + <ItemsControl ItemsSource="{Binding ElementName=control,Path=HorizontalLineEditors}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <local:DiagnosticsGrid Loaded="Rows_DiagnosticsGrid_Loaded" Rows="{Binding ElementName=control,Path=Rows}" Columns="{Binding ElementName=control,Path=ColumnsZero}" /> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Grid.Row" Value="{Binding Position}"></Setter> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border> + <Grid VerticalAlignment="Bottom"> + <Grid Margin="-12 0 0 -5.5"> + <Thumb Height="10" Background="Transparent" Cursor="SizeNS" HorizontalAlignment="Left" DragDelta="Horizontal_Thumb_DragDelta"> + + </Thumb> + + <material:PackIcon Foreground="{StaticResource FSE_PrimaryForegroundBrush}" RenderTransformOrigin="0.5,0.5" Kind="Triangle" IsHitTestVisible="False" Width="12" Height="12"> + <material:PackIcon.RenderTransform> + <RotateTransform Angle="90" /> + </material:PackIcon.RenderTransform> + </material:PackIcon> + </Grid> + <Rectangle IsHitTestVisible="False" Opacity="0.6" StrokeThickness="2" Stroke="{Binding ElementName=control,Path=Foreground}" VerticalAlignment="Bottom"></Rectangle> + </Grid> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + + <Grid Width="125" Height="125" Opacity="0.6" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10"> + <StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" > + <UniformGrid Height="80" Width="40" Rows="2"> + <Button x:Name="btnRemoveRow" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Padding="0" ToolTip="Remove Row" Click="BtnRemoveRow_Click"> + <material:PackIcon Kind="Minus" /> + </Button> + <Button x:Name="btnAddRow" Margin="0 2 0 0" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Padding="0" ToolTip="Add Row" Click="BtnAddRow_Click"> + <material:PackIcon Kind="Plus" /> + </Button> + </UniformGrid> + <TextBlock FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" HorizontalAlignment="Center" Margin="0 5 0 0" Text="{Binding ElementName=control,Path=Rows.Count}"></TextBlock> + </StackPanel> + + <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" > + <UniformGrid Height="40" Width="80" Columns="2"> + <Button x:Name="btnRemoveColumn" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Padding="0" ToolTip="Remove Column" Click="BtnRemoveColumn_Click"> + <material:PackIcon Kind="Minus" /> + </Button> + <Button x:Name="btnAddColumn" Margin="2 0 0 0" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Padding="0" ToolTip="Add Column" Click="BtnAddColumn_Click"> + <material:PackIcon Kind="Plus" /> + </Button> + </UniformGrid> + + <TextBlock FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" VerticalAlignment="Center" Margin="5 0 0 0" Text="{Binding ElementName=control,Path=Columns.Count}"></TextBlock> + </StackPanel> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml.cs new file mode 100644 index 000000000..1aaddedb6 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGridLinesEditor.xaml.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +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.Commands; +using Tango.FSE.Diagnostics.Project; + +namespace Tango.FSE.Diagnostics.Controls +{ + /// <summary> + /// Interaction logic for DiagnosticsGridLinesEditor.xaml + /// </summary> + public partial class DiagnosticsGridLinesEditor : UserControl + { + private DiagnosticsGrid _columnsDiagnosticsGrid; + private DiagnosticsGrid _rowsDiagnosticsGrid; + private const int MAX_LENGTH = 20; + + public class LineEditor + { + public int Position { get; set; } + } + + public ObservableCollection<DiagnosticsProjectTabColumnDefinition> Columns + { + get { return (ObservableCollection<DiagnosticsProjectTabColumnDefinition>)GetValue(ColumnsProperty); } + set { SetValue(ColumnsProperty, value); } + } + public static readonly DependencyProperty ColumnsProperty = + DependencyProperty.Register("Columns", typeof(ObservableCollection<DiagnosticsProjectTabColumnDefinition>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGridLinesEditor).LoadDefinitions())); + + public ObservableCollection<DiagnosticsProjectTabRowDefinition> Rows + { + get { return (ObservableCollection<DiagnosticsProjectTabRowDefinition>)GetValue(RowsProperty); } + set { SetValue(RowsProperty, value); } + } + public static readonly DependencyProperty RowsProperty = + DependencyProperty.Register("Rows", typeof(ObservableCollection<DiagnosticsProjectTabRowDefinition>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGridLinesEditor).LoadDefinitions())); + + public ObservableCollection<DiagnosticsProjectTabColumnDefinition> ColumnsZero + { + get { return (ObservableCollection<DiagnosticsProjectTabColumnDefinition>)GetValue(ColumnsZeroProperty); } + set { SetValue(ColumnsZeroProperty, value); } + } + public static readonly DependencyProperty ColumnsZeroProperty = + DependencyProperty.Register("ColumnsZero", typeof(ObservableCollection<DiagnosticsProjectTabColumnDefinition>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null)); + + public ObservableCollection<DiagnosticsProjectTabRowDefinition> RowsZero + { + get { return (ObservableCollection<DiagnosticsProjectTabRowDefinition>)GetValue(RowsZeroProperty); } + set { SetValue(RowsZeroProperty, value); } + } + public static readonly DependencyProperty RowsZeroProperty = + DependencyProperty.Register("RowsZero", typeof(ObservableCollection<DiagnosticsProjectTabRowDefinition>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null)); + + public List<LineEditor> HorizontalLineEditors + { + get { return (List<LineEditor>)GetValue(HorizontalLineEditorsProperty); } + set { SetValue(HorizontalLineEditorsProperty, value); } + } + public static readonly DependencyProperty HorizontalLineEditorsProperty = + DependencyProperty.Register("HorizontalLineEditors", typeof(List<LineEditor>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null)); + + public List<LineEditor> VerticalLineEditors + { + get { return (List<LineEditor>)GetValue(VerticalLineEditorsProperty); } + set { SetValue(VerticalLineEditorsProperty, value); } + } + public static readonly DependencyProperty VerticalLineEditorsProperty = + DependencyProperty.Register("VerticalLineEditors", typeof(List<LineEditor>), typeof(DiagnosticsGridLinesEditor), new PropertyMetadata(null)); + + public DiagnosticsGridLinesEditor() + { + RowsZero = new ObservableCollection<DiagnosticsProjectTabRowDefinition>(); + ColumnsZero = new ObservableCollection<DiagnosticsProjectTabColumnDefinition>(); + InitializeComponent(); + } + + private void LoadDefinitions() + { + if (Columns != null && Rows != null) + { + List<LineEditor> verticalLines = new List<LineEditor>(); + + for (int columnIndex = 0; columnIndex < Columns.Count; columnIndex++) + { + verticalLines.Add(new LineEditor() { Position = columnIndex }); + } + + List<LineEditor> horizontalLines = new List<LineEditor>(); + + for (int rowIndex = 0; rowIndex < Rows.Count; rowIndex++) + { + horizontalLines.Add(new LineEditor() { Position = rowIndex }); + } + + VerticalLineEditors = verticalLines; + HorizontalLineEditors = horizontalLines; + + Columns.CollectionChanged -= Columns_CollectionChanged; + Rows.CollectionChanged -= Rows_CollectionChanged; + Columns.CollectionChanged += Columns_CollectionChanged; + Rows.CollectionChanged += Rows_CollectionChanged; + } + } + + private void Rows_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + LoadDefinitions(); + } + + private void Columns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + LoadDefinitions(); + } + + private void Vertical_Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) + { + LineEditor line = (sender as FrameworkElement).DataContext as LineEditor; + + if (line.Position == Columns.Count - 1) return; + + var column = Columns[line.Position]; + + foreach (var definition in _columnsDiagnosticsGrid.ColumnDefinitions) + { + if (definition.Width.IsStar) + { + definition.Width = new GridLength(definition.ActualWidth); + } + } + + DiagnosticsProjectTabColumnDefinition nextColumn = null; + + if (line.Position < Columns.Count - 1) + { + nextColumn = Columns[line.Position + 1]; + } + + double oldWidth = column.Width.Value; + double newWidth = Math.Max(column.Width.Value + e.HorizontalChange, MAX_LENGTH); + double delta = newWidth - column.Width.Value; + + if (nextColumn != null) + { + double nextWidth = nextColumn.Width.Value - delta; + + if (nextWidth < MAX_LENGTH) + { + return; + } + } + + column.Width = new GridLength(newWidth); + + if (nextColumn != null) + { + nextColumn.Width = new GridLength(Math.Max(nextColumn.Width.Value - delta, MAX_LENGTH)); + } + } + + private void Horizontal_Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) + { + LineEditor line = (sender as FrameworkElement).DataContext as LineEditor; + + if (line.Position == Rows.Count - 1) return; + + var row = Rows[line.Position]; + + foreach (var definition in _rowsDiagnosticsGrid.RowDefinitions) + { + if (definition.Height.IsStar) + { + definition.Height = new GridLength(definition.ActualHeight); + } + } + + DiagnosticsProjectTabRowDefinition nextRow = null; + + if (line.Position < Rows.Count - 1) + { + nextRow = Rows[line.Position + 1]; + } + + double oldHeight = row.Height.Value; + double newHeight = Math.Max(row.Height.Value + e.VerticalChange, MAX_LENGTH); + double delta = newHeight - row.Height.Value; + + if (nextRow != null) + { + double nextHeight = nextRow.Height.Value - delta; + + if (nextHeight < MAX_LENGTH) + { + return; + } + } + + row.Height = new GridLength(newHeight); + + if (nextRow != null) + { + nextRow.Height = new GridLength(Math.Max(nextRow.Height.Value - delta, MAX_LENGTH)); + } + } + + private void Columns_DiagnosticsGrid_Loaded(object sender, RoutedEventArgs e) + { + _columnsDiagnosticsGrid = sender as DiagnosticsGrid; + } + + private void Rows_DiagnosticsGrid_Loaded(object sender, RoutedEventArgs e) + { + _rowsDiagnosticsGrid = sender as DiagnosticsGrid; + } + + private void BtnRemoveRow_Click(object sender, RoutedEventArgs e) + { + if (Rows.Count > 0) + { + Rows.Remove(Rows.Last()); + } + } + + private void BtnAddRow_Click(object sender, RoutedEventArgs e) + { + Rows.Add(new DiagnosticsProjectTabRowDefinition() { Height = new GridLength(1, GridUnitType.Star) }); + } + + private void BtnRemoveColumn_Click(object sender, RoutedEventArgs e) + { + if (Columns.Count > 0) + { + Columns.Remove(Columns.Last()); + } + } + + private void BtnAddColumn_Click(object sender, RoutedEventArgs e) + { + Columns.Add(new DiagnosticsProjectTabColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsSelectionGrid.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsSelectionGrid.cs new file mode 100644 index 000000000..48e2cbad6 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsSelectionGrid.cs @@ -0,0 +1,202 @@ +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.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Controls +{ + public class DiagnosticsSelectionGrid : DiagnosticsGrid + { + private List<Rectangle> _rects; + private Point _mouseDownLocation; + private bool _isMouseDown; + private List<Rectangle> _selectionRects; + + public Brush RectanglesBackgroundBrush + { + get { return (Brush)GetValue(RectanglesBackgroundBrushProperty); } + set { SetValue(RectanglesBackgroundBrushProperty, value); } + } + public static readonly DependencyProperty RectanglesBackgroundBrushProperty = + DependencyProperty.Register("RectanglesBackgroundBrush", typeof(Brush), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(25, 25, 25)))); + + public Brush RectanglesHighlightBrush + { + get { return (Brush)GetValue(RectanglesHighlightBrushProperty); } + set { SetValue(RectanglesHighlightBrushProperty, value); } + } + public static readonly DependencyProperty RectanglesHighlightBrushProperty = + DependencyProperty.Register("RectanglesHighlightBrush", typeof(Brush), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(30, 30, 30)))); + + public Rect SelectionRect + { + get { return (Rect)GetValue(SelectionRectProperty); } + set { SetValue(SelectionRectProperty, value); } + } + public static readonly DependencyProperty SelectionRectProperty = + DependencyProperty.Register("SelectionRect", typeof(Rect), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(default(Rect))); + + public ICommand SelectionCommand + { + get { return (ICommand)GetValue(SelectionCommandProperty); } + set { SetValue(SelectionCommandProperty, value); } + } + public static readonly DependencyProperty SelectionCommandProperty = + DependencyProperty.Register("SelectionCommand", typeof(ICommand), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(null)); + + public ICommand RightClickCommand + { + get { return (ICommand)GetValue(RightClickCommandProperty); } + set { SetValue(RightClickCommandProperty, value); } + } + public static readonly DependencyProperty RightClickCommandProperty = + DependencyProperty.Register("RightClickCommand", typeof(ICommand), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(null)); + + public SelectionMode SelectionMode + { + get { return (SelectionMode)GetValue(SelectionModeProperty); } + set { SetValue(SelectionModeProperty, value); } + } + public static readonly DependencyProperty SelectionModeProperty = + DependencyProperty.Register("SelectionMode", typeof(SelectionMode), typeof(DiagnosticsSelectionGrid), new PropertyMetadata(SelectionMode.Multiple)); + + static DiagnosticsSelectionGrid() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(DiagnosticsSelectionGrid), new FrameworkPropertyMetadata(typeof(DiagnosticsSelectionGrid))); + } + + public DiagnosticsSelectionGrid() + { + _rects = new List<Rectangle>(); + _selectionRects = new List<Rectangle>(); + Cursor = Cursors.Cross; + Background = Brushes.Transparent; + } + + public void ClearSelection() + { + _selectionRects.Clear(); + foreach (var rect in _rects) + { + rect.Fill = RectanglesBackgroundBrush; + } + } + + protected override void LoadDefinitions() + { + base.LoadDefinitions(); + + if (Rows != null && Columns != null) + { + _rects.Clear(); + _selectionRects.Clear(); + Children.Clear(); + + for (int columnIndex = 0; columnIndex < Columns.Count; columnIndex++) + { + for (int rowIndex = 0; rowIndex < Rows.Count; rowIndex++) + { + var rect = new Rectangle(); + rect.Margin = new Thickness(1); + rect.Fill = RectanglesBackgroundBrush; + rect.IsHitTestVisible = false; + Grid.SetColumn(rect, columnIndex); + Grid.SetRow(rect, rowIndex); + Children.Add(rect); + _rects.Add(rect); + } + } + } + } + + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); + + if (SelectionMode == SelectionMode.Single) return; + + if (e.ChangedButton == MouseButton.Left) + { + _mouseDownLocation = e.GetPosition(this); + _isMouseDown = true; + } + } + + protected override void OnPreviewMouseUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseUp(e); + _isMouseDown = false; + + if (e.ChangedButton == MouseButton.Right) + { + RightClickCommand?.Execute(null); + return; + } + + if (_selectionRects.Count > 0) + { + var column = _selectionRects.Min(x => Grid.GetColumn(x)); + var row = _selectionRects.Min(x => Grid.GetRow(x)); + var columnSpan = Math.Max(_selectionRects.Max(x => Grid.GetColumn(x)) - column + 1, 1); + var rowSpan = Math.Max(_selectionRects.Max(x => Grid.GetRow(x)) - row + 1, 1); + + SelectionRect = new Rect(column, row, columnSpan, rowSpan); + SelectionCommand?.Execute(SelectionRect); + + ClearSelection(); + } + } + + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + + if (SelectionMode == SelectionMode.Single) + { + var position = e.GetPosition(this); + var selection = new Rect(position.X, position.Y, 1, 1); + HighlightIntersections(selection); + } + else if (_isMouseDown) + { + var position = e.GetPosition(this); + + var x = Math.Min(position.X, _mouseDownLocation.X); + var y = Math.Min(position.Y, _mouseDownLocation.Y); + var w = Math.Max(position.X, _mouseDownLocation.X) - Math.Min(_mouseDownLocation.X, position.X); + var h = Math.Max(position.Y, _mouseDownLocation.Y) - Math.Min(_mouseDownLocation.Y, position.Y); + + var selection = new Rect(x, y, w, h); + HighlightIntersections(selection); + } + } + + private void HighlightIntersections(Rect selection) + { + _selectionRects.Clear(); + + foreach (var rect in _rects) + { + GeneralTransform gt = rect.TransformToAncestor(this); + var rectBounds = gt.TransformBounds(new Rect(0, 0, rect.ActualWidth, rect.ActualHeight)); + + if (selection.IntersectsWith(rectBounds)) + { + rect.Fill = RectanglesHighlightBrush; + _selectionRects.Add(rect); + } + else + { + rect.Fill = RectanglesBackgroundBrush; + } + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs index 3ba8f2e4b..ea6d52d0f 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs @@ -20,8 +20,16 @@ namespace Tango.FSE.Diagnostics.Converters if (widget.Settings != null) { var view = widget.Settings.GetView(); - view.DataContext = widget; - return view; + + if (view != null) + { + view.DataContext = widget; + return view; + } + else + { + return null; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs index 439b1a17a..31ee1fbe3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs @@ -17,7 +17,9 @@ namespace Tango.FSE.Diagnostics.Converters if (widget != null) { - return widget.GetView(); + var view = widget.GetView(); + view.DataContext = widget; + return view; } return null; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/ValveStateComparerToBooleanConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/ValveStateComparerToBooleanConverter.cs new file mode 100644 index 000000000..2034c502f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/ValveStateComparerToBooleanConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Converters +{ + public class ValveStateComparerToBooleanConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Length == 2 && values[0] != DependencyProperty.UnsetValue && values[1] != DependencyProperty.UnsetValue) + { + ValveStateCode v1 = (ValveStateCode)values[0]; + ValveStateCode v2 = (ValveStateCode)Enum.Parse(typeof(ValveStateCode), values[1].ToString().Replace(" ", ""), true); + return v1 == v2; + } + else + { + return false; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs index 48fe8c186..9e81f0bc7 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs @@ -13,6 +13,8 @@ namespace Tango.FSE.Diagnostics { public class DiagnosticsPackage { + private static Dictionary<String, PropertyInfo> _monitorsProperties; + /// <summary> /// Gets or sets the frame. /// </summary> @@ -21,14 +23,27 @@ namespace Tango.FSE.Diagnostics /// <summary> /// Gets or sets the monitors properties. /// </summary> - public Dictionary<String, PropertyInfo> MonitorsProperties { get; set; } + public Dictionary<String, PropertyInfo> MonitorsProperties { get; private set; } + + /// <summary> + /// Initializes the <see cref="DiagnosticsPackage"/> class. + /// </summary> + static DiagnosticsPackage() + { + _monitorsProperties = new Dictionary<string, PropertyInfo>(); + + foreach (var prop in typeof(DiagnosticsMonitors).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList()) + { + _monitorsProperties.Add(prop.Name, prop); + } + } /// <summary> /// Initializes a new instance of the <see cref="DiagnosticsPackage"/> class. /// </summary> public DiagnosticsPackage() { - MonitorsProperties = new Dictionary<string, PropertyInfo>(); + MonitorsProperties = _monitorsProperties; } /// <summary> @@ -77,5 +92,35 @@ namespace Tango.FSE.Diagnostics DoubleArray[] arrayOfDoubles = Enumerable.ToArray(value as IEnumerable<DoubleArray>); return arrayOfDoubles.Select(x => x.Data.ToList()).ToList(); } + + /// <summary> + /// Gets the state of the digital interface. + /// </summary> + /// <param name="interface">The interface.</param> + /// <returns></returns> + public DigitalInterfaceState GetDigitalInterfaceState(TechIos @interface) + { + return Frame.Data.DigitalInterfaceStates.SingleOrDefault(x => x.InterfaceIO == (InterfaceIOs)@interface); + } + + /// <summary> + /// Gets the state of the specified valve. + /// </summary> + /// <param name="valve">The valve.</param> + /// <returns></returns> + public ValveState GetValveState(TechValves valve) + { + return Frame.Data.ValvesStates.SingleOrDefault(x => x.ValveType == (ValveType)valve); + } + + /// <summary> + /// Gets the state of the specified heater. + /// </summary> + /// <param name="heater">The heater.</param> + /// <returns></returns> + public HeaterState GetHeaterState(TechHeaters heater) + { + return Frame.Data.HeatersStates.SingleOrDefault(x => x.HeaterType == (HeaterType)heater); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsSettings.cs new file mode 100644 index 000000000..94475e72c --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsSettings.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Settings; + +namespace Tango.FSE.Diagnostics +{ + public class DiagnosticsSettings : SettingsBase + { + + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs index ac1d29847..90ad17055 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs @@ -8,34 +8,21 @@ namespace Tango.FSE.Diagnostics.Project { public abstract class DiagnosticsConfigurableWidget : DiagnosticsWidget { - public DiagnosticsWidgetSettings Settings { get; set; } - } - - public abstract class DiagnosticsConfigurableWidget<T> : DiagnosticsConfigurableWidget where T : DiagnosticsWidgetSettings, new() - { - private T _settings; - public new T Settings + private DiagnosticsWidgetSettings _settings; + public DiagnosticsWidgetSettings Settings { get { return _settings; } set { _settings = value; - RaisePropertyChangedAuto(); - - if (_settings != null) + if (value != null) { - base.Settings = value; OnSettingsChanged(); - _settings.PropertyChanged += _settings_PropertyChanged; + value.PropertyChanged += _settings_PropertyChanged; } } } - public DiagnosticsConfigurableWidget() : base() - { - Settings = new T(); - } - private void _settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { OnSettingsChanged(); @@ -46,4 +33,22 @@ namespace Tango.FSE.Diagnostics.Project } } + + public abstract class DiagnosticsConfigurableWidget<T> : DiagnosticsConfigurableWidget where T : DiagnosticsWidgetSettings, new() + { + public new T Settings + { + get { return base.Settings as T; } + set + { + base.Settings = value; + RaisePropertyChangedAuto(); + } + } + + public DiagnosticsConfigurableWidget() : base() + { + Settings = new T(); + } + } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs index bc93f4101..aae0709d8 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs @@ -11,15 +11,21 @@ using Tango.Core; namespace Tango.FSE.Diagnostics.Project { public class DiagnosticsProject : ExtendedObject - { - private static JsonSerializerSettings _settings; + { + public static JsonSerializerSettings JsonSettings { get; private set; } public String Name { get; set; } + public ObservableCollection<DiagnosticsProjectTab> Tabs { get; set; } + public List<DiagnosticsWidget> FlattenWidgets() + { + return Tabs.SelectMany(x => x.Widgets).ToList(); + } + static DiagnosticsProject() { - _settings = new JsonSerializerSettings() + JsonSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented @@ -34,12 +40,12 @@ namespace Tango.FSE.Diagnostics.Project public String ToJson() { - return JsonConvert.SerializeObject(this, _settings); + return JsonConvert.SerializeObject(this, JsonSettings); } public static DiagnosticsProject FromJson(String json) { - return JsonConvert.DeserializeObject<DiagnosticsProject>(json, _settings); + return JsonConvert.DeserializeObject<DiagnosticsProject>(json, JsonSettings); } public void ToFile(String fileName) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs index d50a6aa0d..aab776137 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs @@ -13,15 +13,49 @@ namespace Tango.FSE.Diagnostics.Project public class DiagnosticsProjectTab : ExtendedObject { public String Name { get; set; } - public List<DiagnosticsProjectTabColumnDefinition> Columns { get; set; } - public List<DiagnosticsProjectTabRowDefinition> Rows { get; set; } + public ObservableCollection<DiagnosticsProjectTabColumnDefinition> Columns { get; set; } + public ObservableCollection<DiagnosticsProjectTabRowDefinition> Rows { get; set; } public ObservableCollection<DiagnosticsWidget> Widgets { get; set; } public DiagnosticsProjectTab() { - Columns = new List<DiagnosticsProjectTabColumnDefinition>(); - Rows = new List<DiagnosticsProjectTabRowDefinition>(); + Columns = new ObservableCollection<DiagnosticsProjectTabColumnDefinition>(); + Rows = new ObservableCollection<DiagnosticsProjectTabRowDefinition>(); Widgets = new ObservableCollection<DiagnosticsWidget>(); } + + public static DiagnosticsProjectTab CreateNew(String name, int columns, int rows) + { + var tab = new DiagnosticsProjectTab(); + tab.Name = name; + + for (int i = 0; i < columns; i++) + { + tab.Columns.Add(CreateColumn()); + } + + for (int i = 0; i < rows; i++) + { + tab.Rows.Add(CreateRow()); + } + + return tab; + } + + private static DiagnosticsProjectTabColumnDefinition CreateColumn() + { + return new DiagnosticsProjectTabColumnDefinition() + { + Width = new GridLength(1, GridUnitType.Star) + }; + } + + private static DiagnosticsProjectTabRowDefinition CreateRow() + { + return new DiagnosticsProjectTabRowDefinition() + { + Height = new GridLength(1, GridUnitType.Star) + }; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs index 3f10fa793..efffb4308 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs @@ -4,11 +4,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using Tango.Core; namespace Tango.FSE.Diagnostics.Project { - public class DiagnosticsProjectTabColumnDefinition + public class DiagnosticsProjectTabColumnDefinition : ExtendedObject { - public GridLength Width { get; set; } + private GridLength _width; + public GridLength Width + { + get { return _width; } + set { _width = value; RaisePropertyChangedAuto(); } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs index 0797d89ac..e889ec979 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs @@ -4,11 +4,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using Tango.Core; namespace Tango.FSE.Diagnostics.Project { - public class DiagnosticsProjectTabRowDefinition + public class DiagnosticsProjectTabRowDefinition : ExtendedObject { - public GridLength Height { get; set; } + private GridLength _height; + public GridLength Height + { + get { return _height; } + set { _height = value; RaisePropertyChangedAuto(); } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsCollection.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsCollection.cs new file mode 100644 index 000000000..35bc164b9 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsCollection.cs @@ -0,0 +1,100 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.ExtensionMethods; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsUserSettingsCollection + { + private static JsonSerializerSettings _settings; + + public List<DiagnosticsUserWidgetSettings> Widgets { get; set; } + + public T GetWidgetSettings<T>(DiagnosticsConfigurableWidget widget) where T : DiagnosticsWidgetSettings + { + return GetWidgetSettings(widget) as T; + } + + public DiagnosticsWidgetSettings GetWidgetSettings(DiagnosticsConfigurableWidget widget) + { + var record = Widgets.FirstOrDefault(x => x.WidgetID == widget.ID); + if (record != null) + { + return record.Settings; + } + + return null; + } + + public void ApplyWidgetSettings(DiagnosticsConfigurableWidget widget) + { + var record = Widgets.FirstOrDefault(x => x.WidgetID == widget.ID); + if (record != null) + { + if (widget.Settings == null) + { + widget.Settings = record.Settings; + } + else + { + record.Settings.MapPropertiesTo(widget.Settings, MappingFlags.All, (prop) => prop.GetCustomAttribute<JsonIgnoreAttribute>() == null); + } + } + } + + public void SetWidgetSettings(DiagnosticsConfigurableWidget widget) + { + var record = Widgets.FirstOrDefault(x => x.WidgetID == widget.ID); + if (record == null) + { + record = new DiagnosticsUserWidgetSettings() + { + WidgetID = widget.ID, + }; + Widgets.Add(record); + } + + record.Settings = widget.Settings; + } + + static DiagnosticsUserSettingsCollection() + { + _settings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.Auto, + Formatting = Formatting.Indented + }; + } + + public DiagnosticsUserSettingsCollection() + { + Widgets = new List<DiagnosticsUserWidgetSettings>(); + } + + public String ToJson() + { + return JsonConvert.SerializeObject(this, _settings); + } + + public static DiagnosticsUserSettingsCollection FromJson(String json) + { + return JsonConvert.DeserializeObject<DiagnosticsUserSettingsCollection>(json, _settings); + } + + public void ToFile(String fileName) + { + File.WriteAllText(fileName, ToJson()); + } + + public static DiagnosticsUserSettingsCollection FromFile(String fileName) + { + return FromJson(File.ReadAllText(fileName)); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsManager.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsManager.cs new file mode 100644 index 000000000..1e3684733 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserSettingsManager.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsUserSettingsManager : ExtendedObject + { + private static object _syncLock = new object(); + + private static DiagnosticsUserSettingsManager _default; + public static DiagnosticsUserSettingsManager Default + { + get + { + if (_default == null) + { + _default = new DiagnosticsUserSettingsManager(); + } + + return _default; + } + } + + public String FilePath { get; protected set; } + + public DiagnosticsUserSettingsCollection Settings { get; set; } + + private DiagnosticsUserSettingsManager() + { + Settings = new DiagnosticsUserSettingsCollection(); + FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Diagnostics", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".User.json"); + Reload(); + } + + public void Reload() + { + try + { + Settings = DiagnosticsUserSettingsCollection.FromFile(FilePath); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading diagnostics user settings."); + } + } + + public void ClearGhostRecords(List<DiagnosticsConfigurableWidget> widgets) + { + Settings.Widgets.RemoveAll(x => !widgets.Exists(y => y.ID == x.WidgetID)); + } + + public void Save() + { + lock (_syncLock) + { + Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); + Settings.ToFile(FilePath); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserWidgetSettings.cs new file mode 100644 index 000000000..855bd31f9 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsUserWidgetSettings.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsUserWidgetSettings + { + public String WidgetID { get; set; } + public DiagnosticsWidgetSettings Settings { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs index c7880909b..ad63dd8b1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs @@ -2,9 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Controls; +using Tango.BL.Enumerations; using Tango.Core; using Tango.Core.DI; using Tango.FSE.BL; @@ -15,7 +18,7 @@ using Tango.PMR.Diagnostics; namespace Tango.FSE.Diagnostics.Project { - public abstract class DiagnosticsWidget : ExtendedObject + public abstract class DiagnosticsWidget : ExtendedObject, IDisposable { [JsonIgnore] [TangoInject(TangoInjectMode.WhenAvailable)] @@ -38,12 +41,63 @@ namespace Tango.FSE.Diagnostics.Project set { _services = value; OnServicesAvailable(); } } - public int Column { get; set; } - public int Row { get; set; } - public int ColumnSpan { get; set; } - public int RowSpan { get; set; } - public double Width { get; set; } - public double Height { get; set; } + public String ID { get; set; } + + private int _column; + public int Column + { + get { return _column; } + set { _column = value; RaisePropertyChangedAuto(); } + } + + private int _row; + public int Row + { + get { return _row; } + set { _row = value; RaisePropertyChangedAuto(); } + } + + private int _columnSpan; + public int ColumnSpan + { + get { return _columnSpan; } + set { _columnSpan = value; RaisePropertyChangedAuto(); } + } + + private int _rowSpan; + public int RowSpan + { + get { return _rowSpan; } + set { _rowSpan = value; RaisePropertyChangedAuto(); } + } + + private double _width; + public double Width + { + get { return _width; } + set { _width = value; RaisePropertyChangedAuto(); } + } + + private double _height; + public double Height + { + get { return _height; } + set { _height = value; RaisePropertyChangedAuto(); } + } + + private bool _displayComponentName; + public bool DisplayComponentName + { + get { return _displayComponentName; } + set { _displayComponentName = value; RaisePropertyChangedAuto(); } + } + + private Dock _componentNameAlignment; + public Dock ComponentNameAlignment + { + get { return _componentNameAlignment; } + set { _componentNameAlignment = value; RaisePropertyChangedAuto(); } + } private bool _isVisible; [JsonIgnore] @@ -61,16 +115,64 @@ namespace Tango.FSE.Diagnostics.Project } } + private bool _isSelected; + [JsonIgnore] + public bool IsSelected + { + get { return _isSelected; } + set { _isSelected = value; RaisePropertyChangedAuto(); } + } + [JsonIgnore] public abstract String DisplayName { get; } + [JsonIgnore] + public bool SupportsComponentSelection + { + get + { + return this is ISupportsComponentSelection; + } + } + + [JsonIgnore] + public bool IsCurrentUserEditor + { + get + { + return AuthenticationProvider.CurrentUser.HasPermission(Permissions.FSE_EditDiagnosticsProject); + } + } + + [JsonIgnore] + public virtual bool HasSettings + { + get + { + return (this is DiagnosticsConfigurableWidget) || (SupportsComponentSelection && (this as ISupportsComponentSelection).EnableComponentSelection); + } + } + + private bool _editMode; + [JsonIgnore] + public bool EditMode + { + get { return _editMode; } + set { _editMode = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasSettings)); } + } + + [JsonIgnore] + public bool IsDisposed { get; protected set; } + public DiagnosticsWidget() { + ID = Guid.NewGuid().ToString(); Width = 100; Height = 100; + ComponentNameAlignment = Dock.Top; TangoIOC.Default.Inject(this); } @@ -79,7 +181,10 @@ namespace Tango.FSE.Diagnostics.Project } - public abstract void OnDiagnosticsData(DiagnosticsPackage package); + public virtual void OnDiagnosticsData(DiagnosticsPackage package) + { + //Do Nothing. + } protected virtual void OnVisibleChanged(bool isVisible) { @@ -92,5 +197,28 @@ namespace Tango.FSE.Diagnostics.Project { return Task.FromResult(true); } + + protected async void InitAsync() + { + await Init(); + } + + public DiagnosticsWidget Clone() + { + var json = JsonConvert.SerializeObject(this, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }); + var cloned = JsonConvert.DeserializeObject(json, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }) as DiagnosticsWidget; + cloned.ID = Guid.NewGuid().ToString(); + return cloned; + } + + public void RaiseHasSettings() + { + RaisePropertyChanged(nameof(HasSettings)); + } + + public virtual void Dispose() + { + IsDisposed = true; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetComponent.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetComponent.cs new file mode 100644 index 000000000..c680ed0b1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetComponent.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsWidgetComponent<T> + { + public String DisplayName { get; set; } + public T Object { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/ISupportsComponentSelection.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/ISupportsComponentSelection.cs new file mode 100644 index 000000000..41ddd6a3a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/ISupportsComponentSelection.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Diagnostics.Project +{ + public interface ISupportsComponentSelection + { + bool EnableComponentSelection { get; set; } + } + + public interface ISupportsComponentSelection<T> : ISupportsComponentSelection + { + [JsonIgnore] + List<DiagnosticsWidgetComponent<T>> Components { get; } + + [JsonIgnore] + T SelectedComponent { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidget.cs new file mode 100644 index 000000000..d311e0c71 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidget.cs @@ -0,0 +1,218 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core; +using Tango.Core.Commands; +using Tango.FSE.Common.Notifications; +using Tango.FSE.Diagnostics.Project.Widgets.Motor; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Dispenser +{ + [Description("Dispenser Controller")] + public class DispenserWidget : DiagnosticsConfigurableWidget<DispenserWidgetSettings>, ISupportsComponentSelection<TechDispensers> + { + public TechDispensers Dispenser { get; set; } + + private TechDispenser _techDispenser; + [JsonIgnore] + public TechDispenser TechDispenser + { + get { return _techDispenser; } + set { _techDispenser = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechDispenser != null ? this.TechDispenser.Description : String.Empty; + } + } + + private MotorWidgetState _state; + [JsonIgnore] + public MotorWidgetState State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsHoming)); } + } + + [JsonIgnore] + public bool IsHoming + { + get { return State == MotorWidgetState.HomingBackward || State == MotorWidgetState.HomingForward; } + } + + private TangoProgress<double> _homingProgress; + [JsonIgnore] + public TangoProgress<double> HomingProgress + { + get { return _homingProgress; } + set { _homingProgress = value; RaisePropertyChangedAuto(); } + } + + [JsonIgnore] + public RelayCommand<MotorWidgetState> ExecuteCommand { get; set; } + + [JsonIgnore] + public RelayCommand StopCommand { get; set; } + + public DispenserWidget() + { + HomingProgress = new TangoProgress<double>(null, false, 0, 100); + + ExecuteCommand = new RelayCommand<MotorWidgetState>(Execute); + StopCommand = new RelayCommand(StopCurrentExecution); + } + + public override async Task Init() + { + int motor = (int)Dispenser; + TechDispenser = await Services.TechComponentsService.Dispensers.FindOne(x => x.Code == motor); + } + + public override FrameworkElement GetView() + { + return new DispenserWidgetView(); + } + + private async void Execute(MotorWidgetState command) + { + if (!MachineProvider.IsConnected || State != MotorWidgetState.Idle) return; + + State = command; + HomingProgress = new TangoProgress<double>(null, true, 0, 100); + + TaskCompletionSource<object> completion = null; + + try + { + if (command == MotorWidgetState.JoggingForward || command == MotorWidgetState.JoggingBackward) + { + await MachineProvider.MachineOperator.StartDispenserJogging(new DispenserJoggingRequest() + { + Index = (int)Dispenser, + Direction = command == MotorWidgetState.JoggingForward ? MotorDirection.Forward : MotorDirection.Backward, + Speed = Settings.Speed + }); + } + else if (command == MotorWidgetState.HomingForward || command == MotorWidgetState.HomingBackward) + { + completion = new TaskCompletionSource<object>(); + + MachineProvider.MachineOperator.StartDispenserHoming(new DispenserHomingRequest() + { + Index = (int)Dispenser, + Speed = Settings.Speed, + Direction = command == MotorWidgetState.HomingForward ? MotorDirection.Forward : MotorDirection.Backward + }) + .Subscribe((response) => + { + HomingProgress = new TangoProgress<double>(null, response.Progress == 0, response.Progress, response.MaxProgress); + }, (ex) => + { + completion.SetException(ex); + }, () => + { + State = MotorWidgetState.Idle; + completion.SetResult(true); + }); + } + + if (completion != null) + { + await completion.Task; + } + } + catch (Exception ex) + { + if (State != MotorWidgetState.Idle) + { + State = MotorWidgetState.Idle; + LogManager.Log(ex, $"Error occurred in diagnostics dispenser widget '{command}'."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Dispenser Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + finally + { + HomingProgress = new TangoProgress<double>(null, false); + } + } + + private async void StopCurrentExecution() + { + if (!MachineProvider.IsConnected) return; + + var command = State; + + State = MotorWidgetState.Idle; + HomingProgress = new TangoProgress<double>(null, false); + + try + { + if (command == MotorWidgetState.JoggingForward || command == MotorWidgetState.JoggingBackward) + { + await MachineProvider.MachineOperator.StopDispenserJogging(new DispenserAbortJoggingRequest() + { + Index = (int)Dispenser, + }); + } + else if (command == MotorWidgetState.HomingForward || command == MotorWidgetState.HomingBackward) + { + await MachineProvider.MachineOperator.StopDispenserHoming(new DispenserAbortHomingRequest() + { + Index = (int)Dispenser, + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error occurred in diagnostics dispenser widget '{command}'."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Dispenser Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<TechDispensers>> Components + { + get + { + return Services.TechComponentsService.Dispensers.FindAll().Result.Select(x => new DiagnosticsWidgetComponent<TechDispensers>() + { + DisplayName = x.Description, + Object = (TechDispensers)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechDispensers SelectedComponent + { + get + { + return Dispenser; + } + set + { + if (Dispenser != value) + { + Dispenser = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettings.cs new file mode 100644 index 000000000..c205c56cf --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Dispenser +{ + public class DispenserWidgetSettings : DiagnosticsWidgetSettings + { + private int _speed; + public int Speed + { + get { return _speed; } + set { _speed = value; RaisePropertyChangedAuto(); } + } + + private Color _color; + public Color Color + { + get { return _color; } + set { _color = value; RaisePropertyChangedAuto(); } + } + + public DispenserWidgetSettings() + { + Speed = 400; + Color = Color.FromRgb(20, 20, 20); + } + + public override FrameworkElement GetView() + { + return new DispenserWidgetSettingsView(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml new file mode 100644 index 000000000..1f288dc10 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml @@ -0,0 +1,27 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Dispenser.DispenserWidgetSettingsView" + 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:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Dispenser" + mc:Ignorable="d" + d:DesignHeight="700" d:DesignWidth="300" d:DataContext="{d:DesignInstance Type=local:DispenserWidgetSettings,IsDesignTimeCreatable=False}"> + <Grid> + <StackPanel> + <controls:FSEGroupBox Header="SPEED" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <mahapps:NumericUpDown Minimum="0" Maximum="10000" Value="{Binding Settings.Speed,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="COLOR" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Viewbox> + <colorPicker:ColorCanvas Background="Transparent" BorderThickness="0" FontSize="{StaticResource FSE_SmallerFontSize}" SelectedColor="{Binding Settings.Color,Mode=TwoWay}" /> + </Viewbox> + </controls:FSEGroupBox> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..fd4d992a2 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Dispenser +{ + /// <summary> + /// Interaction logic for DispenserWidgetSettingsView.xaml + /// </summary> + public partial class DispenserWidgetSettingsView : UserControl + { + public DispenserWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml new file mode 100644 index 000000000..75294c59d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml @@ -0,0 +1,185 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Dispenser.DispenserWidgetView" + 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:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Dispenser" + xmlns:motor="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Motor" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="640" d:DataContext="{d:DesignInstance Type=local:DispenserWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox Stretch="Uniform"> + <Grid Width="320" Height="400" Margin="70 0 0 0"> + <Grid.LayoutTransform> + <RotateTransform Angle="-90" /> + </Grid.LayoutTransform> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="25*"/> + <ColumnDefinition Width="100*"/> + <ColumnDefinition Width="25*"/> + </Grid.ColumnDefinitions> + + <Grid.RowDefinitions> + <RowDefinition Height="87*" /> + <RowDefinition Height="18*" /> + </Grid.RowDefinitions> + + <Grid Grid.Column="1"> + <Border BorderThickness="1" BorderBrush="{StaticResource FSE_BorderBrush}" CornerRadius="10" Background="#252525"> + <Grid> + <Grid.LayoutTransform> + <RotateTransform Angle="90" /> + </Grid.LayoutTransform> + <Image Stretch="Fill" Source="../Dispenser/Images/dispenser_line.png" /> + <Path HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="100" RenderTransformOrigin="0.5,0.5" StrokeThickness="1" Stretch="Uniform" Margin="10" Data="M500.633 211.454l-58.729-14.443c-3.53-11.133-8.071-21.929-13.55-32.256c8.818-14.678 27.349-45.571 27.349-45.571 c3.545-5.903 2.607-13.462-2.256-18.325l-42.422-42.422c-4.863-4.878-12.407-5.815-18.325-2.256L347.055 83.53 c-10.269-5.435-21.006-9.932-32.065-13.433l-14.443-58.729C298.876 4.688 292.885 0 286 0h-60 c-6.885 0-12.891 4.688-14.546 11.367c0 0-10.005 40.99-14.429 58.715c-11.792 3.735-23.188 8.584-34.043 14.502l-47.329-28.403 c-5.918-3.516-13.447-2.607-18.325 2.256l-42.422 42.422c-4.863 4.863-5.801 12.422-2.256 18.325l29.268 48.882 c-4.717 9.302-8.672 18.984-11.821 28.901l-58.729 14.487C4.688 213.124 0 219.115 0 226v60c0 6.885 4.688 12.891 11.367 14.546 l58.744 14.443c3.56 11.294 8.188 22.266 13.799 32.798l-26.191 43.652c-3.545 5.903-2.607 13.462 2.256 18.325l42.422 42.422 c4.849 4.849 12.407 5.771 18.325 2.256c0 0 29.37-17.607 43.755-26.221c10.415 5.552 21.313 10.137 32.549 13.696l14.429 58.715 C213.109 507.313 219.115 512 226 512h60c6.885 0 12.876-4.688 14.546-11.367l14.429-58.715 c11.558-3.662 22.69-8.394 33.281-14.136c14.78 8.862 44.443 26.66 44.443 26.66c5.903 3.53 13.462 2.622 18.325-2.256 l42.422-42.422c4.863-4.863 5.801-12.422 2.256-18.325l-26.968-44.927c5.317-10.093 9.727-20.654 13.169-31.523l58.729-14.443 C507.313 298.876 512 292.885 512 286v-60C512 219.115 507.313 213.124 500.633 211.454z M256 361c-57.891 0-105-47.109-105-105 s47.109-105 105-105s105 47.109 105 105S313.891 361 256 361z"> + <Path.Stroke> + <SolidColorBrush Color="{Binding Settings.Color}" /> + </Path.Stroke> + <Path.Style> + <Style TargetType="Path"> + <Setter Property="RenderTransform"> + <Setter.Value> + <RotateTransform x:Name="propRotate" Angle="0" /> + </Setter.Value> + </Setter> + <Style.Triggers> + + <DataTrigger Binding="{Binding State}" Value="{x:Static motor:MotorWidgetState.JoggingForward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="joggingForward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="joggingForward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static motor:MotorWidgetState.JoggingBackward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="joggingBackward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="-360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="joggingBackward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static motor:MotorWidgetState.HomingForward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="homingForward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="homingForward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static motor:MotorWidgetState.HomingBackward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="homingBackward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="-360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="homingBackward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + </Style.Triggers> + </Style> + </Path.Style> + <Path.Fill> + <LinearGradientBrush> + <GradientStop Color="Black"/> + <GradientStop Color="Transparent" Offset="0.8"/> + </LinearGradientBrush> + </Path.Fill> + </Path> + </Grid> + </Border> + </Grid> + + <Grid> + <Button Margin="0 60" Style="{StaticResource FSE_MotorWidgetButton_Left}" IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseDown"> + <i:InvokeCommandAction Command="{Binding ExecuteCommand}" CommandParameter="{x:Static motor:MotorWidgetState.JoggingBackward}" /> + </i:EventTrigger> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding StopCommand}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Viewbox Stretch="Fill" Margin="-10 20"> + <material:PackIcon Kind="ChevronLeft" HorizontalAlignment="Center" VerticalAlignment="Center" Width="24" Height="24" /> + </Viewbox> + </Button> + </Grid> + + <Grid Grid.Column="2"> + <Button Margin="0 60" Style="{StaticResource FSE_MotorWidgetButton_Right}" IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseDown"> + <i:InvokeCommandAction Command="{Binding ExecuteCommand}" CommandParameter="{x:Static motor:MotorWidgetState.JoggingForward}" /> + </i:EventTrigger> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding StopCommand}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Viewbox Stretch="Fill" Margin="-10 20"> + <material:PackIcon Kind="ChevronRight" HorizontalAlignment="Center" VerticalAlignment="Center" Width="24" Height="24" /> + </Viewbox> + </Button> + </Grid> + + <Grid Grid.Column="1" Grid.Row="1" Visibility="Visible"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="20*"/> + <ColumnDefinition Width="115*"/> + <ColumnDefinition Width="20*"/> + </Grid.ColumnDefinitions> + + <Grid Grid.Column="1"> + <Border Style="{StaticResource FSE_MotorWidgetBorder_Center}"> + <Grid x:Name="gridDefault"> + <DockPanel> + <controls:IconButton IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}" Margin="5 0 0 0" HorizontalAlignment="Center" Command="{Binding ExecuteCommand}" CommandParameter="{x:Static motor:MotorWidgetState.HomingBackward}" Width="40" Height="40" Style="{StaticResource FSE_WidgetIconButton_Red}" DockPanel.Dock="Left" Icon="ChevronDoubleLeft"></controls:IconButton> + <controls:IconButton IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}" HorizontalAlignment="Center" Command="{Binding ExecuteCommand}" CommandParameter="{x:Static motor:MotorWidgetState.HomingForward}" Width="40" Height="40" Style="{StaticResource FSE_WidgetIconButton_Red}" DockPanel.Dock="Right" Icon="ChevronDoubleRight"></controls:IconButton> + + <Grid> + <Grid.LayoutTransform> + <RotateTransform Angle="90" /> + </Grid.LayoutTransform> + <material:PackIcon Margin="-5 0 0 0" Visibility="{Binding IsHoming,Converter={StaticResource BooleanToVisibilityInverseConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Padding="0" Width="55" Height="55" Kind="Home"></material:PackIcon> + + <Grid Visibility="{Binding IsHoming,Converter={StaticResource BooleanToVisibilityConverter}}"> + + <Viewbox Margin="0 5 5 5"> + <controls:ProgressRingDouble HorizontalAlignment="Center" VerticalAlignment="Center" Minimum="0" Maximum="100" IsIndeterminate="{Binding HomingProgress.IsIndeterminate}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Value="{Binding HomingProgress.Value}" Thickness="5" Width="70" Height="70" /> + </Viewbox> + + <controls:IconButton Cursor="Hand" Padding="0" Command="{Binding StopCommand}" Icon="Stop" Width="42" Height="42" Foreground="{StaticResource FSE_RedBrush}" HorizontalAlignment="Center" VerticalAlignment="Center"></controls:IconButton> + </Grid> + </Grid> + </DockPanel> + </Grid> + </Border> + </Grid> + </Grid> + </Grid> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml.cs new file mode 100644 index 000000000..24af229a8 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/DispenserWidgetView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Dispenser +{ + /// <summary> + /// Interaction logic for DispenserWidgetView.xaml + /// </summary> + public partial class DispenserWidgetView : UserControl + { + public DispenserWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/Images/dispenser_line.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/Images/dispenser_line.png Binary files differnew file mode 100644 index 000000000..9e2e344c0 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Dispenser/Images/dispenser_line.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidget.cs new file mode 100644 index 000000000..ed10f3088 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidget.cs @@ -0,0 +1,153 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.FSE.Common.Notifications; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Heater +{ + [Description("Heater Controller")] + public class HeaterWidget : DiagnosticsWidget, ISupportsComponentSelection<TechHeaters> + { + public TechHeaters Heater { get; set; } + + private TechHeater _techHeater; + [JsonIgnore] + public TechHeater TechHeater + { + get { return _techHeater; } + set { _techHeater = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechHeater != null ? this.TechHeater.Description : String.Empty; + } + } + + private HeaterState _heaterState; + [JsonIgnore] + public HeaterState HeaterState + { + get { return _heaterState; } + set + { + _heaterState = value; + RaisePropertyChangedAuto(); + + if (!IsEditing) + { + SetPoint = _heaterState.SetPoint; + } + + InvokeUI(() => + { + SetCommand?.RaiseCanExecuteChanged(); + }); + } + } + + private double _setPoint; + public double SetPoint + { + get { return _setPoint; } + set { _setPoint = value; RaisePropertyChangedAuto(); } + } + + private bool _isEditing; + [JsonIgnore] + public bool IsEditing + { + get { return _isEditing; } + set { _isEditing = value; RaisePropertyChangedAuto(); } + } + + [JsonIgnore] + public RelayCommand SetCommand { get; set; } + + public HeaterWidget() + { + SetCommand = new RelayCommand(SetHeaterState, (x) => HeaterState.CurrentValue != SetPoint); + HeaterState = new HeaterState(); + } + + public override async Task Init() + { + int heater = (int)Heater; + TechHeater = await Services.TechComponentsService.Heaters.FindOne(x => x.Code == heater); + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + base.OnDiagnosticsData(package); + HeaterState = package.GetHeaterState(Heater); + } + + private async void SetHeaterState() + { + if (MachineProvider.IsConnected) + { + try + { + IsEditing = false; + await MachineProvider.MachineOperator.SetHeaterState((HeaterType)Heater, SetPoint); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error executing SetHeaterState command for heater {Heater}."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Heater Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + } + + public override FrameworkElement GetView() + { + return new HeaterWidgetView(); + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<TechHeaters>> Components + { + get + { + return Services.TechComponentsService.Heaters.FindAll().Result.Select(x => new DiagnosticsWidgetComponent<TechHeaters>() + { + DisplayName = x.Description, + Object = (TechHeaters)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechHeaters SelectedComponent + { + get + { + return Heater; + } + set + { + if (Heater != value) + { + Heater = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml new file mode 100644 index 000000000..056d591ba --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml @@ -0,0 +1,202 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Heater.HeaterWidgetView" + 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.FSE.Diagnostics.Project.Widgets.Heater" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + mc:Ignorable="d" + d:DesignHeight="284" d:DesignWidth="243" d:DataContext="{d:DesignInstance Type=local:HeaterWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox> + <Border CornerRadius="5" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderBrush="#3B3B3B" BorderThickness="1" Padding="15"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="16"/> + <RowDefinition Height="74"/> + <RowDefinition Height="63"/> + <RowDefinition Height="37"/> + <RowDefinition/> + </Grid.RowDefinitions> + + <Grid> + <TextBlock FontFamily="{StaticResource digital-7}" Text="Heater Controller" FontSize="16" Foreground="#7CC924" HorizontalAlignment="Left" Width="123"></TextBlock> + <TextBlock HorizontalAlignment="Right" Text="TEMPERATURE" FontSize="9" VerticalAlignment="Bottom" Foreground="Gainsboro" Height="12" Width="58"></TextBlock> + </Grid> + + <Grid Grid.Row="1"> + <Border Background="{StaticResource FSE_PrimaryBackgroundMidBrush}" Margin="0 3 0 0" CornerRadius="3" Padding="5"> + <Grid> + <TextBlock Text="{Binding HeaterState.CurrentValue,StringFormat=0.00,FallbackValue='0.00'}" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="80" FontFamily="{StaticResource digital-7}" Margin="0 0 12 0"> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Foreground" Value="#FF6F78"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding HeaterState.IsInSetPoint}" Value="True"> + <Setter Property="Foreground" Value="#7CC924"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + <TextBlock ToolTip="Process Value" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="9" Foreground="Gainsboro">PV</TextBlock> + </Grid> + </Border> + </Grid> + + <Grid Grid.Row="2" Margin="0 5 0 0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="49"/> + <ColumnDefinition Width="162"/> + </Grid.ColumnDefinitions> + + <Image Source="../Heater/Images/temperature.png" Margin="0 10 20 10" RenderOptions.BitmapScalingMode="Fant"></Image> + + <Border Background="{StaticResource FSE_PrimaryBackgroundMidBrush}" Margin="0 3 0 0" CornerRadius="3" Padding="5" Grid.Column="1"> + <Grid> + <mahapps:NumericUpDown x:Name="txtSetPoint" InterceptMouseWheel="True" IsHitTestVisible="{Binding IsEditing}" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Right" HideUpDownButtons="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HasDecimals="True" Minimum="0" Maximum="400" Padding="0" Value="{Binding SetPoint,FallbackValue='0.0',Mode=TwoWay}" VerticalAlignment="Center" FontSize="44" FontFamily="{StaticResource digital-7}" Foreground="#FFD400" Margin="0 0 12 0"> + <mahapps:NumericUpDown.Resources> + <Style TargetType="TextBox"> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="CaretBrush" Value="#FFD400"></Setter> + <Setter Property="SelectionBrush" Value="#50FFD400"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsEditing}" Value="True"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="blink"> + <Storyboard> + <DoubleAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetProperty="Opacity" FillBehavior="Stop"> + <DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" /> + <DiscreteDoubleKeyFrame KeyTime="00:00:0.5" Value="1" /> + <DiscreteDoubleKeyFrame KeyTime="00:00:1" Value="1" /> + </DoubleAnimationUsingKeyFrames> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="blink" /> + </DataTrigger.ExitActions> + </DataTrigger> + </Style.Triggers> + </Style> + </mahapps:NumericUpDown.Resources> + + <mahapps:NumericUpDown.Style> + <Style TargetType="mahapps:NumericUpDown"> + + </Style> + </mahapps:NumericUpDown.Style> + </mahapps:NumericUpDown> + <TextBlock ToolTip="Setting Value" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="9" Foreground="Gainsboro">SV</TextBlock> + + <ToggleButton Checked="ToggleButton_Checked" Style="{x:Null}" IsChecked="{Binding IsEditing}" HorizontalAlignment="Left" VerticalAlignment="Top" Opacity="0.2" Cursor="Hand"> + <ToggleButton.Template> + <ControlTemplate TargetType="ToggleButton"> + <Grid Background="Transparent"> + <material:PackIcon Width="24" Height="24" Foreground="#FFD400"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="Kind" Value="PencilBox"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsEditing}" Value="True"> + <Setter Property="Kind" Value="Pencil"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </Grid> + </Border> + </Grid> + + <Grid Grid.Row="3" Margin="0 5 0 0"> + <StackPanel Orientation="Horizontal" TextElement.Foreground="Gray" TextElement.FontSize="9"> + <StackPanel> + <TextBlock>ACTIVE</TextBlock> + <Ellipse Width="12" Height="12" Margin="0 4 0 0" Fill="#FF6262" Stroke="#526744"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Opacity" Value="0.2"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding HeaterState.IsActive}" Value="True"> + <Setter Property="Opacity" Value="1"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + </StackPanel> + + <StackPanel Margin="10 0 0 0"> + <TextBlock>RAMP UP</TextBlock> + <Ellipse Width="12" Height="12" Margin="0 4 0 0" Fill="#FF8608" Stroke="#526744"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Opacity" Value="0.2"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding HeaterState.IsRampingUp}" Value="True"> + <Setter Property="Opacity" Value="1"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + </StackPanel> + + <StackPanel Margin="10 0 0 0"> + <TextBlock>IN POINT</TextBlock> + <Ellipse Width="12" Height="12" Margin="0 4 0 0" Fill="#00C600" Stroke="#526744"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Opacity" Value="0.2"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding HeaterState.IsInSetPoint}" Value="True"> + <Setter Property="Opacity" Value="1"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + </StackPanel> + </StackPanel> + </Grid> + + <Grid Grid.Row="4"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="36"/> + <ColumnDefinition Width="175"/> + </Grid.ColumnDefinitions> + + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" FontSize="16" FontWeight="SemiBold">TWI</TextBlock> + + <Grid Grid.Column="1"> + <Button Style="{x:Null}" Width="60" Height="60" HorizontalAlignment="Right" Cursor="Hand" Command="{Binding SetCommand}" IsEnabled="{Binding IsEditing}"> + <Button.Template> + <ControlTemplate TargetType="Button"> + <Grid> + <Ellipse Stroke="#7C7C7C" Fill="#383838"></Ellipse> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gainsboro" FontSize="16" FontWeight="SemiBold">SET</TextBlock> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Opacity" Value="0.7"></Setter> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Opacity" Value="0.5"></Setter> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Button.Template> + </Button> + </Grid> + </Grid> + </Grid> + </Border> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml.cs new file mode 100644 index 000000000..efd532179 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/HeaterWidgetView.xaml.cs @@ -0,0 +1,34 @@ +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.FSE.Diagnostics.Project.Widgets.Heater +{ + /// <summary> + /// Interaction logic for HeaterWidgetView.xaml + /// </summary> + public partial class HeaterWidgetView : UserControl + { + public HeaterWidgetView() + { + InitializeComponent(); + } + + private void ToggleButton_Checked(object sender, RoutedEventArgs e) + { + txtSetPoint.Focus(); + txtSetPoint.SelectAll(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/Images/temperature.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/Images/temperature.png Binary files differnew file mode 100644 index 000000000..0bd30c002 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Heater/Images/temperature.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidget.cs new file mode 100644 index 000000000..2c2309807 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidget.cs @@ -0,0 +1,106 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Input +{ + [Description("Digital Input LED")] + public class InputWidget : DiagnosticsWidget, ISupportsComponentSelection<TechIos> + { + public TechIos IO { get; set; } = TechIos.LS_DH_CLEAN_DOWN; + + private TechIo _techIO; + [JsonIgnore] + public TechIo TechIo + { + get { return _techIO; } + set { _techIO = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechIo != null ? this.TechIo.InterfaceName : String.Empty; + } + } + + private bool _value; + [JsonIgnore] + public bool Value + { + get { return _value; } + set + { + if (_value != value) + { + _value = value; + RaisePropertyChangedAuto(); + } + } + } + + public override async Task Init() + { + int io = (int)IO; + TechIo = await Services.TechComponentsService.IOs.FindOne(x => x.Code == io); + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + var state = package.GetDigitalInterfaceState(IO); + + if (state != null) + { + Value = state.Value; + } + } + + public override FrameworkElement GetView() + { + return new InputWidgetView(); + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<TechIos>> Components + { + get + { + return Services.TechComponentsService.IOs.FindAll().Result.Where(x => x.Type == (int)IOType.DigitalInput).Select(x => new DiagnosticsWidgetComponent<TechIos>() + { + DisplayName = x.InterfaceName, + Object = (TechIos)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechIos SelectedComponent + { + get + { + return IO; + } + set + { + if (IO != value) + { + IO = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml new file mode 100644 index 000000000..9049f90d1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml @@ -0,0 +1,18 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Input.InputWidgetView" + 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:visuals="clr-namespace:Tango.Visuals;assembly=Tango.Visuals" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Input" + mc:Ignorable="d" + d:DesignHeight="83" d:DesignWidth="72" d:DataContext="{d:DesignInstance Type=local:InputWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox> + <Grid> + <Ellipse Width="100" Height="100" Fill="{StaticResource FSE_PrimaryBackgroundMidBrush}"></Ellipse> + <visuals:Led Width="100" Height="100" IsChecked="{Binding Value}" IsHitTestVisible="False" /> + </Grid> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml.cs new file mode 100644 index 000000000..22ed571e8 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Input/InputWidgetView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Input +{ + /// <summary> + /// Interaction logic for InputWidgetView.xaml + /// </summary> + public partial class InputWidgetView : UserControl + { + public InputWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs index 3a2590ca2..611897191 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs @@ -1,6 +1,7 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,12 +11,18 @@ using Tango.BL.Enumerations; namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor { - public class MonitorWidget : DiagnosticsConfigurableWidget<MonitorWidgetSettings> + [Description("Monitor")] + public class MonitorWidget : DiagnosticsConfigurableWidget<MonitorWidgetSettings>, ISupportsComponentSelection<TechMonitors> { public TechMonitors Monitor { get; set; } + private TechMonitor _techMonitor; [JsonIgnore] - public TechMonitor TechMonitor { get; private set; } + public TechMonitor TechMonitor + { + get { return _techMonitor; } + set { _techMonitor = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } [JsonIgnore] public override string DisplayName @@ -31,7 +38,14 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor public String Value { get { return _value; } - set { _value = value; RaisePropertyChangedAuto(); } + set + { + if (_value != value) + { + _value = value; + RaisePropertyChangedAuto(); + } + } } public override async Task Init() @@ -62,7 +76,41 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor public override FrameworkElement GetView() { - return new MonitorWidgetView() { DataContext = this }; + return new MonitorWidgetView(); + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<TechMonitors>> Components + { + get + { + return Services.TechComponentsService.Monitors.FindAll().Result.Where(x => !x.MultiChannel).Select(x => new DiagnosticsWidgetComponent<TechMonitors>() + { + DisplayName = x.Description, + Object = (TechMonitors)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechMonitors SelectedComponent + { + get + { + return Monitor; + } + set + { + if (Monitor != value) + { + Monitor = value; + InitAsync(); + } + } } + + public bool EnableComponentSelection { get; set; } + + #endregion } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml index 9ddaea737..bd18da646 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml @@ -14,7 +14,7 @@ <controls:FSEGroupBox Header="FORMAT" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> <StackPanel> <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> - <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + <mahapps:NumericUpDown Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> </StackPanel> </controls:FSEGroupBox> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml index 1d8ba96a6..0dc2d96ac 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml @@ -7,22 +7,30 @@ mc:Ignorable="d" d:DesignHeight="250" d:DesignWidth="400" d:DataContext="{d:DesignInstance Type=local:MonitorWidget,IsDesignTimeCreatable=False}"> <Grid> - <Viewbox Stretch="Fill"> + <Viewbox Stretch="Uniform"> <StackPanel> - <Grid Grid.Column="1" Grid.Row="1" Width="200" Height="120"> - <Border BorderThickness="0" BorderBrush="{StaticResource AccentColorBrush}"> - <Border.Background> - <ImageBrush ImageSource="../Monitor/Images/tft_screen.png" Opacity="1" /> - </Border.Background> - + <Grid Grid.Column="1" Grid.Row="1" Width="400" Height="250"> + <Border BorderThickness="1" BorderBrush="{StaticResource FSE_BorderBrush}" CornerRadius="10"> <Grid> - <Viewbox Stretch="Uniform" Width="150" VerticalAlignment="Center" Margin="25 10 10 10" HorizontalAlignment="Left"> - <TextBlock FontFamily="{StaticResource digital-7}" TextAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="90" Text="{Binding Value,FallbackValue='0000'}"> - <TextBlock.Foreground> - <SolidColorBrush Color="{Binding Settings.Color}"></SolidColorBrush> - </TextBlock.Foreground> - </TextBlock> - </Viewbox> + <Border BorderBrush="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="35" CornerRadius="1" Margin="1"> + <Border BorderThickness="2" Background="#353535"> + <Border.BorderBrush> + <LinearGradientBrush> + <GradientStop Offset="0.8" Color="{StaticResource FSE_PrimaryBackgroundLightColor}" /> + <GradientStop Offset="0" Color="#121212" /> + </LinearGradientBrush> + </Border.BorderBrush> + <Viewbox Stretch="Uniform" Width="270" VerticalAlignment="Center" Margin="25 0 10 0" HorizontalAlignment="Left"> + <Border> + <TextBlock FontFamily="{StaticResource digital-7}" TextAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="90" Text="{Binding Value,FallbackValue='0000',TargetNullValue='0000'}"> + <TextBlock.Foreground> + <SolidColorBrush Color="{Binding Settings.Color}"></SolidColorBrush> + </TextBlock.Foreground> + </TextBlock> + </Border> + </Viewbox> + </Border> + </Border> </Grid> </Border> </Grid> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidget.cs new file mode 100644 index 000000000..28fed7c9d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidget.cs @@ -0,0 +1,219 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core; +using Tango.Core.Commands; +using Tango.FSE.Common.Notifications; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Motor +{ + [Description("Motor Controller")] + public class MotorWidget : DiagnosticsConfigurableWidget<MotorWidgetSettings>, ISupportsComponentSelection<HardwareMotorTypes> + { + public HardwareMotorTypes Motor { get; set; } + + + private HardwareMotorType _hardwareMotorType; + [JsonIgnore] + public HardwareMotorType HardwareMotorType + { + get { return _hardwareMotorType; } + set { _hardwareMotorType = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.HardwareMotorType != null ? this.HardwareMotorType.Description : String.Empty; + } + } + + private MotorWidgetState _state; + [JsonIgnore] + public MotorWidgetState State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsHoming)); } + } + + [JsonIgnore] + public bool IsHoming + { + get { return State == MotorWidgetState.HomingBackward || State == MotorWidgetState.HomingForward; } + } + + private TangoProgress<double> _homingProgress; + [JsonIgnore] + public TangoProgress<double> HomingProgress + { + get { return _homingProgress; } + set { _homingProgress = value; RaisePropertyChangedAuto(); } + } + + [JsonIgnore] + public RelayCommand<MotorWidgetState> ExecuteCommand { get; set; } + + [JsonIgnore] + public RelayCommand StopCommand { get; set; } + + public MotorWidget() + { + HomingProgress = new TangoProgress<double>(null, false, 0, 100); + + ExecuteCommand = new RelayCommand<MotorWidgetState>(Execute); + StopCommand = new RelayCommand(StopCurrentExecution); + } + + public override async Task Init() + { + int motor = (int)Motor; + HardwareMotorType = await Services.TechComponentsService.Motors.FindOne(x => x.Code == motor); + } + + public override FrameworkElement GetView() + { + return new MotorWidgetView(); + } + + private async void Execute(MotorWidgetState command) + { + if (!MachineProvider.IsConnected || State != MotorWidgetState.Idle) return; + + State = command; + HomingProgress = new TangoProgress<double>(null, true, 0, 100); + + TaskCompletionSource<object> completion = null; + + try + { + if (command == MotorWidgetState.JoggingForward || command == MotorWidgetState.JoggingBackward) + { + await MachineProvider.MachineOperator.StartMotorJogging(new MotorJoggingRequest() + { + MotorType = (PMR.Hardware.HardwareMotorType)Motor, + Direction = command == MotorWidgetState.JoggingForward ? MotorDirection.Forward : MotorDirection.Backward, + Speed = Settings.Speed + }); + } + else if (command == MotorWidgetState.HomingForward || command == MotorWidgetState.HomingBackward) + { + completion = new TaskCompletionSource<object>(); + + MachineProvider.MachineOperator.StartMotorHoming(new MotorHomingRequest() + { + MotorType = (PMR.Hardware.HardwareMotorType)Motor, + Speed = Settings.Speed, + Direction = command == MotorWidgetState.HomingForward ? MotorDirection.Forward : MotorDirection.Backward + }) + .Subscribe((response) => + { + HomingProgress = new TangoProgress<double>(null, response.Progress == 0, response.Progress, response.MaxProgress); + }, (ex) => + { + completion.SetException(ex); + }, () => + { + State = MotorWidgetState.Idle; + completion.SetResult(true); + }); + } + + if (completion != null) + { + await completion.Task; + } + } + catch (Exception ex) + { + if (State != MotorWidgetState.Idle) + { + State = MotorWidgetState.Idle; + LogManager.Log(ex, $"Error occurred in diagnostics motor widget '{command}'."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Motor Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + finally + { + HomingProgress = new TangoProgress<double>(null, false); + } + } + + private async void StopCurrentExecution() + { + if (!MachineProvider.IsConnected) return; + + var command = State; + + State = MotorWidgetState.Idle; + HomingProgress = new TangoProgress<double>(null, false); + + try + { + if (command == MotorWidgetState.JoggingForward || command == MotorWidgetState.JoggingBackward) + { + await MachineProvider.MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest() + { + MotorType = (PMR.Hardware.HardwareMotorType)Motor, + }); + } + else if (command == MotorWidgetState.HomingForward || command == MotorWidgetState.HomingBackward) + { + await MachineProvider.MachineOperator.StopMotorHoming(new MotorAbortHomingRequest() + { + MotorType = (PMR.Hardware.HardwareMotorType)Motor, + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error occurred in diagnostics motor widget '{command}'."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Motor Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<HardwareMotorTypes>> Components + { + get + { + return Services.TechComponentsService.Motors.FindAll().Result.Select(x => new DiagnosticsWidgetComponent<HardwareMotorTypes>() + { + DisplayName = x.Description, + Object = (HardwareMotorTypes)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public HardwareMotorTypes SelectedComponent + { + get + { + return Motor; + } + set + { + if (Motor != value) + { + Motor = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettings.cs new file mode 100644 index 000000000..b68b57910 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Motor +{ + public class MotorWidgetSettings : DiagnosticsWidgetSettings + { + private int _speed; + public int Speed + { + get { return _speed; } + set { _speed = value; RaisePropertyChangedAuto(); } + } + + private Color _color; + public Color Color + { + get { return _color; } + set { _color = value; RaisePropertyChangedAuto(); } + } + + public MotorWidgetSettings() + { + Speed = 400; + Color = Color.FromRgb(20, 20, 20); + } + + public override FrameworkElement GetView() + { + return new MotorWidgetSettingsView(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml new file mode 100644 index 000000000..3dabb5aef --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml @@ -0,0 +1,27 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Motor.MotorWidgetSettingsView" + 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:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Motor" + mc:Ignorable="d" + d:DesignHeight="700" d:DesignWidth="300" d:DataContext="{d:DesignInstance Type=local:MotorWidgetSettings,IsDesignTimeCreatable=False}"> + <Grid> + <StackPanel> + <controls:FSEGroupBox Header="SPEED" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <mahapps:NumericUpDown Minimum="0" Maximum="10000" Value="{Binding Settings.Speed,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="COLOR" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Viewbox> + <colorPicker:ColorCanvas Background="Transparent" BorderThickness="0" FontSize="{StaticResource FSE_SmallerFontSize}" SelectedColor="{Binding Settings.Color,Mode=TwoWay}" /> + </Viewbox> + </controls:FSEGroupBox> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..b26f0c130 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Motor +{ + /// <summary> + /// Interaction logic for MotorWidgetSettingsView.xaml + /// </summary> + public partial class MotorWidgetSettingsView : UserControl + { + public MotorWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetState.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetState.cs new file mode 100644 index 000000000..0075c6038 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetState.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Motor +{ + public enum MotorWidgetState + { + Idle, + JoggingForward, + JoggingBackward, + HomingForward, + HomingBackward + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml new file mode 100644 index 000000000..b2582676c --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml @@ -0,0 +1,175 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Motor.MotorWidgetView" + 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:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Motor" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="640" d:DataContext="{d:DesignInstance Type=local:MotorWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox Stretch="Uniform"> + <Grid Width="400" Height="280"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="20*"/> + <ColumnDefinition Width="100*"/> + <ColumnDefinition Width="20*"/> + </Grid.ColumnDefinitions> + + <Grid.RowDefinitions> + <RowDefinition Height="100*" /> + <RowDefinition Height="30*" /> + </Grid.RowDefinitions> + + <Grid Grid.Column="1"> + <Border BorderThickness="1" BorderBrush="{StaticResource FSE_BorderBrush}" CornerRadius="10" Background="#252525"> + <Grid Margin="20"> + <Path RenderTransformOrigin="0.5,0.5" StrokeThickness="1" Stretch="Uniform" Margin="10" Data="M500.633 211.454l-58.729-14.443c-3.53-11.133-8.071-21.929-13.55-32.256c8.818-14.678 27.349-45.571 27.349-45.571 c3.545-5.903 2.607-13.462-2.256-18.325l-42.422-42.422c-4.863-4.878-12.407-5.815-18.325-2.256L347.055 83.53 c-10.269-5.435-21.006-9.932-32.065-13.433l-14.443-58.729C298.876 4.688 292.885 0 286 0h-60 c-6.885 0-12.891 4.688-14.546 11.367c0 0-10.005 40.99-14.429 58.715c-11.792 3.735-23.188 8.584-34.043 14.502l-47.329-28.403 c-5.918-3.516-13.447-2.607-18.325 2.256l-42.422 42.422c-4.863 4.863-5.801 12.422-2.256 18.325l29.268 48.882 c-4.717 9.302-8.672 18.984-11.821 28.901l-58.729 14.487C4.688 213.124 0 219.115 0 226v60c0 6.885 4.688 12.891 11.367 14.546 l58.744 14.443c3.56 11.294 8.188 22.266 13.799 32.798l-26.191 43.652c-3.545 5.903-2.607 13.462 2.256 18.325l42.422 42.422 c4.849 4.849 12.407 5.771 18.325 2.256c0 0 29.37-17.607 43.755-26.221c10.415 5.552 21.313 10.137 32.549 13.696l14.429 58.715 C213.109 507.313 219.115 512 226 512h60c6.885 0 12.876-4.688 14.546-11.367l14.429-58.715 c11.558-3.662 22.69-8.394 33.281-14.136c14.78 8.862 44.443 26.66 44.443 26.66c5.903 3.53 13.462 2.622 18.325-2.256 l42.422-42.422c4.863-4.863 5.801-12.422 2.256-18.325l-26.968-44.927c5.317-10.093 9.727-20.654 13.169-31.523l58.729-14.443 C507.313 298.876 512 292.885 512 286v-60C512 219.115 507.313 213.124 500.633 211.454z M256 361c-57.891 0-105-47.109-105-105 s47.109-105 105-105s105 47.109 105 105S313.891 361 256 361z"> + <Path.Stroke> + <SolidColorBrush Color="{Binding Settings.Color}" /> + </Path.Stroke> + <Path.Style> + <Style TargetType="Path"> + <Setter Property="RenderTransform"> + <Setter.Value> + <RotateTransform x:Name="propRotate" Angle="0" /> + </Setter.Value> + </Setter> + <Style.Triggers> + + <DataTrigger Binding="{Binding State}" Value="{x:Static local:MotorWidgetState.JoggingForward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="joggingForward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="joggingForward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static local:MotorWidgetState.JoggingBackward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="joggingBackward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="-360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="joggingBackward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static local:MotorWidgetState.HomingForward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="homingForward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="homingForward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + <DataTrigger Binding="{Binding State}" Value="{x:Static local:MotorWidgetState.HomingBackward}"> + <DataTrigger.EnterActions> + <BeginStoryboard Name="homingBackward"> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="-360" Duration="00:00:01" RepeatBehavior="Forever" FillBehavior="HoldEnd" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <RemoveStoryboard BeginStoryboardName="homingBackward" /> + </DataTrigger.ExitActions> + </DataTrigger> + + </Style.Triggers> + </Style> + </Path.Style> + <Path.Fill> + <LinearGradientBrush> + <GradientStop Color="Black"/> + <GradientStop Color="Transparent" Offset="0.8"/> + </LinearGradientBrush> + </Path.Fill> + </Path> + </Grid> + </Border> + </Grid> + + <Grid> + <Button Margin="0 10" Style="{StaticResource FSE_MotorWidgetButton_Left}" IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseDown"> + <i:InvokeCommandAction Command="{Binding ExecuteCommand}" CommandParameter="{x:Static local:MotorWidgetState.JoggingBackward}" /> + </i:EventTrigger> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding StopCommand}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Viewbox Stretch="Fill" Margin="-10 20"> + <material:PackIcon Kind="ChevronLeft" HorizontalAlignment="Center" VerticalAlignment="Center" Width="24" Height="24" /> + </Viewbox> + </Button> + </Grid> + + <Grid Grid.Column="2"> + <Button Margin="0 10" Style="{StaticResource FSE_MotorWidgetButton_Right}" IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseDown"> + <i:InvokeCommandAction Command="{Binding ExecuteCommand}" CommandParameter="{x:Static local:MotorWidgetState.JoggingForward}" /> + </i:EventTrigger> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding StopCommand}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Viewbox Stretch="Fill" Margin="-10 20"> + <material:PackIcon Kind="ChevronRight" HorizontalAlignment="Center" VerticalAlignment="Center" Width="24" Height="24" /> + </Viewbox> + </Button> + </Grid> + + <Grid Grid.Column="1" Grid.Row="1" Visibility="Visible"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="20*"/> + <ColumnDefinition Width="115*"/> + <ColumnDefinition Width="20*"/> + </Grid.ColumnDefinitions> + + <Grid Grid.Column="1"> + <Border Style="{StaticResource FSE_MotorWidgetBorder_Center}"> + <Grid x:Name="gridDefault"> + <DockPanel> + <controls:IconButton IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}" Margin="5 0 0 0" HorizontalAlignment="Center" Command="{Binding ExecuteCommand}" CommandParameter="{x:Static local:MotorWidgetState.HomingBackward}" Width="40" Height="40" Style="{StaticResource FSE_WidgetIconButton_Red}" DockPanel.Dock="Left" Icon="ChevronDoubleLeft"></controls:IconButton> + <controls:IconButton IsEnabled="{Binding IsHoming,Converter={StaticResource BooleanInverseConverter}}" HorizontalAlignment="Center" Command="{Binding ExecuteCommand}" CommandParameter="{x:Static local:MotorWidgetState.HomingForward}" Width="40" Height="40" Style="{StaticResource FSE_WidgetIconButton_Red}" DockPanel.Dock="Right" Icon="ChevronDoubleRight"></controls:IconButton> + + <Grid> + <material:PackIcon Margin="-5 0 0 0" Visibility="{Binding IsHoming,Converter={StaticResource BooleanToVisibilityInverseConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Padding="0" Width="55" Height="55" Kind="Home"></material:PackIcon> + + <Grid Visibility="{Binding IsHoming,Converter={StaticResource BooleanToVisibilityConverter}}"> + + <Viewbox Margin="0 5 5 5"> + <controls:ProgressRingDouble HorizontalAlignment="Center" VerticalAlignment="Center" Minimum="0" Maximum="100" IsIndeterminate="{Binding HomingProgress.IsIndeterminate}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Value="{Binding HomingProgress.Value}" Thickness="5" Width="70" Height="70" /> + </Viewbox> + + <controls:IconButton Cursor="Hand" Padding="0" Command="{Binding StopCommand}" Icon="Stop" Width="42" Height="42" Foreground="{StaticResource FSE_RedBrush}" HorizontalAlignment="Center" VerticalAlignment="Center"></controls:IconButton> + </Grid> + </Grid> + </DockPanel> + </Grid> + </Border> + </Grid> + </Grid> + + </Grid> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml.cs new file mode 100644 index 000000000..7fc9f6343 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Motor/MotorWidgetView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Motor +{ + /// <summary> + /// Interaction logic for MotorWidgetView.xaml + /// </summary> + public partial class MotorWidgetView : UserControl + { + public MotorWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs index 50693746e..98358f9b0 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs @@ -3,6 +3,7 @@ using RealTimeGraphX.DataPoints; using RealTimeGraphX.WPF; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; @@ -15,6 +16,7 @@ using Tango.Core.Commands; namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph { + [Description("Single Series Graph")] public class RealTimeGraphWidget : RealTimeGraphWidgetBase<RealTimeGraphWidgetSettings> { diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs index 8e79e53e3..8fbed469c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs @@ -15,12 +15,17 @@ using Tango.Core.Commands; namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph { - public abstract class RealTimeGraphWidgetBase<T> : DiagnosticsConfigurableWidget<T> where T : RealTimeGraphWidgetSettings, new() + public abstract class RealTimeGraphWidgetBase<T> : DiagnosticsConfigurableWidget<T>, ISupportsComponentSelection<TechMonitors> where T : RealTimeGraphWidgetSettings, new() { public TechMonitors Monitor { get; set; } + private TechMonitor _techMonitor; [JsonIgnore] - public TechMonitor TechMonitor { get; private set; } + public TechMonitor TechMonitor + { + get { return _techMonitor; } + set { _techMonitor = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } [JsonIgnore] public override string DisplayName @@ -62,13 +67,14 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph public override async Task Init() { + Clear(); int monitor = (int)Monitor; TechMonitor = await Services.TechComponentsService.Monitors.FindOne(x => x.Code == monitor); } public override FrameworkElement GetView() { - return new RealTimeGraphWidgetView() { DataContext = this }; + return new RealTimeGraphWidgetView(); } protected override void OnVisibleChanged(bool isVisible) @@ -118,5 +124,39 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph Controller.PushData(dates, dPoints); } } + + #region Component Selection + + public virtual List<DiagnosticsWidgetComponent<TechMonitors>> Components + { + get + { + return Services.TechComponentsService.Monitors.FindAll().Result.Where(x => !x.MultiChannel).Select(x => new DiagnosticsWidgetComponent<TechMonitors>() + { + DisplayName = x.Description, + Object = (TechMonitors)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechMonitors SelectedComponent + { + get + { + return Monitor; + } + set + { + if (Monitor != value) + { + Monitor = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml index 333f21b76..073d9dc23 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml @@ -43,14 +43,14 @@ LowerValue="{Binding Settings.Min,UpdateSourceTrigger=PropertyChanged}" UpperValue="{Binding Settings.Max,UpdateSourceTrigger=PropertyChanged}"/> - <CheckBox Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> + <CheckBox FontSize="{StaticResource FSE_SmallFontSize}" Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> </StackPanel> </controls:FSEGroupBox> <controls:FSEGroupBox Header="FORMAT" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> <StackPanel> <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> - <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + <mahapps:NumericUpDown Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> </StackPanel> </controls:FSEGroupBox> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs index 1ebaa199e..1b1390f15 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs @@ -2,18 +2,26 @@ using RealTimeGraphX.WPF; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; +using Tango.BL.Enumerations; using Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph; namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel { + [Description("Multi Series Graph")] public class RealTimeGraphMultiChannelWidget : RealTimeGraphWidgetBase<RealTimeGraphMultiChannelWidgetSettings> { + public RealTimeGraphMultiChannelWidget() + { + Monitor = TechMonitors.DispensersPressure; + } + public async override Task Init() { await base.Init(); @@ -30,48 +38,61 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() { Name = $"{TechMonitor.Name.First()}{i + 1}", - Stroke = Colors.DodgerBlue, + Stroke = Colors.DimGray, }); } MachineProvider.MachineConnected -= MachineProvider_MachineConnected; MachineProvider.MachineConnected += MachineProvider_MachineConnected; - } - public override FrameworkElement GetView() - { - return new RealTimeGraphMultiChannelWidgetView() { DataContext = this }; + ConfigureByConnectedMachine(); } - private void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e) + private void ConfigureByConnectedMachine() { - try + if (MachineProvider.IsConnected && MachineProvider.Machine != null) { - foreach (var pack in MachineProvider.Machine.Configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex).ToList()) + try { - Color color = Colors.DodgerBlue; + Controller.DataSeriesCollection.ToList().ForEach(x => x.IsVisible = false); - if (pack.LiquidType.LiquidTypeColor == Colors.Black) - { - color = Colors.Gray; - } - else if (pack.LiquidType.LiquidTypeColor == Colors.Transparent) - { - color = Colors.White; - } - else + foreach (var pack in MachineProvider.Machine.Configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex).ToList()) { - color = pack.LiquidType.LiquidTypeColor; - } + Color color = Colors.DimGray; - Controller.DataSeriesCollection[pack.PackIndex].Name = pack.LiquidType.Name; - Controller.DataSeriesCollection[pack.PackIndex].Stroke = color; + if (pack.LiquidType.LiquidTypeColor == Colors.Black) + { + color = Colors.Gray; + } + else if (pack.LiquidType.LiquidTypeColor == Colors.Transparent) + { + color = Colors.White; + } + else + { + color = pack.LiquidType.LiquidTypeColor; + } + + Controller.DataSeriesCollection[pack.PackIndex].Name = pack.LiquidType.Name; + Controller.DataSeriesCollection[pack.PackIndex].Stroke = color; + Controller.DataSeriesCollection[pack.PackIndex].IsVisible = true; + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error initializing colors for real-time multi channel graph data series collection '{Monitor}'."); } } - catch (Exception ex) - { - LogManager.Log(ex, $"Error initializing colors for real-time multi channel graph data series collection '{Monitor}'."); - } + } + + public override FrameworkElement GetView() + { + return new RealTimeGraphMultiChannelWidgetView(); + } + + private void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e) + { + ConfigureByConnectedMachine(); } public override void OnDiagnosticsData(DiagnosticsPackage package) @@ -110,5 +131,17 @@ namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel } } } + + public override List<DiagnosticsWidgetComponent<TechMonitors>> Components + { + get + { + return Services.TechComponentsService.Monitors.FindAll().Result.Where(x => x.MultiChannel).Select(x => new DiagnosticsWidgetComponent<TechMonitors>() + { + DisplayName = x.Description, + Object = (TechMonitors)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml index 0ac731be0..253b1e5ac 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml @@ -43,14 +43,14 @@ LowerValue="{Binding Settings.Min,UpdateSourceTrigger=PropertyChanged}" UpperValue="{Binding Settings.Max,UpdateSourceTrigger=PropertyChanged}"/> - <CheckBox Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> + <CheckBox FontSize="{StaticResource FSE_SmallFontSize}" Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> </StackPanel> </controls:FSEGroupBox> <controls:FSEGroupBox Header="FORMAT" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> <StackPanel> <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> - <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + <mahapps:NumericUpDown Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> </StackPanel> </controls:FSEGroupBox> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidget.cs new file mode 100644 index 000000000..65ac33341 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidget.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Text +{ + public class TextWidget : DiagnosticsConfigurableWidget<TextWidgetSettings> + { + [JsonIgnore] + public override string DisplayName + { + get + { + return Text; + } + } + + private String _text; + public String Text + { + get { return _text; } + set { _text = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + private Color _color; + public Color Color + { + get { return _color; } + set { _color = value; RaisePropertyChangedAuto(); } + } + + [JsonIgnore] + public override bool HasSettings + { + get + { + return EditMode; + } + } + + public TextWidget() + { + Color = Colors.LightGray; + Text = "press to edit text"; + } + + public override FrameworkElement GetView() + { + return new TextWidgetView(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettings.cs new file mode 100644 index 000000000..b0701e56b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettings.cs @@ -0,0 +1,20 @@ +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.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Text +{ + [Description("Text")] + public class TextWidgetSettings : DiagnosticsWidgetSettings + { + public override FrameworkElement GetView() + { + return new TextWidgetSettingsView(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml new file mode 100644 index 000000000..520326643 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml @@ -0,0 +1,24 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Text.TextWidgetSettingsView" + 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:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Text" + mc:Ignorable="d" + d:DesignHeight="700" d:DesignWidth="300" d:DataContext="{d:DesignInstance Type=local:TextWidget,IsDesignTimeCreatable=False}"> + <Grid> + <StackPanel> + <controls:FSEGroupBox Header="TEXT" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </controls:FSEGroupBox> + <controls:FSEGroupBox Header="COLOR" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Viewbox> + <colorPicker:ColorCanvas Background="Transparent" BorderThickness="0" FontSize="{StaticResource FSE_SmallerFontSize}" SelectedColor="{Binding Color,Mode=TwoWay}" /> + </Viewbox> + </controls:FSEGroupBox> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..34cf21cc3 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Text +{ + /// <summary> + /// Interaction logic for TextWidgetSettingsView.xaml + /// </summary> + public partial class TextWidgetSettingsView : UserControl + { + public TextWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml new file mode 100644 index 000000000..cf034f28b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml @@ -0,0 +1,18 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Text.TextWidgetView" + 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.FSE.Diagnostics.Project.Widgets.Text" + mc:Ignorable="d" + d:DesignHeight="100" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:TextWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox Stretch="Uniform"> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Text}" FontSize="16"> + <TextBlock.Foreground> + <SolidColorBrush Color="{Binding Color}" /> + </TextBlock.Foreground> + </TextBlock> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml.cs new file mode 100644 index 000000000..cd354d7fc --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Text/TextWidgetView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Text +{ + /// <summary> + /// Interaction logic for TextWidgetView.xaml + /// </summary> + public partial class TextWidgetView : UserControl + { + public TextWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/Images/valve.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/Images/valve.png Binary files differnew file mode 100644 index 000000000..5c08d0fc5 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/Images/valve.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidget.cs new file mode 100644 index 000000000..89f2b04e5 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidget.cs @@ -0,0 +1,150 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.FSE.Common.Notifications; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Valve +{ + [Description("Valve Controller")] + public class ValveWidget : DiagnosticsWidget, ISupportsComponentSelection<TechValves> + { + public TechValves Valve { get; set; } + + private TechValve _techValve; + [JsonIgnore] + public TechValve TechValve + { + get { return _techValve; } + set { _techValve = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(DisplayName)); } + } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechValve != null ? this.TechValve.Description : String.Empty; + } + } + + private ValveStateCode _state; + [JsonIgnore] + public ValveStateCode State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); } + } + + private ValveStateCode _effectiveState; + [JsonIgnore] + public ValveStateCode EffectiveState + { + get { return _effectiveState; } + set + { + if (_effectiveState != value) + { + _effectiveState = value; + RaisePropertyChangedAuto(); + _state = value; + RaisePropertyChanged(nameof(State)); + } + } + } + + [JsonIgnore] + public RelayCommand<String> SetCommand { get; set; } + + public ValveWidget() + { + SetCommand = new RelayCommand<string>(CommitState); + } + + private async void CommitState(string command) + { + try + { + State = (ValveStateCode)Enum.Parse(typeof(ValveStateCode), command.Replace(" ", ""), true); + + if (MachineProvider.IsConnected) + { + await MachineProvider.MachineOperator.SetValveState((ValveType)Valve, State); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error setting valve state."); + NotificationProvider.PushSnackbarItem(MessageType.Error, "Valve Controller Error", true, ex.Message, TimeSpan.FromSeconds(5)); + } + } + + public override async Task Init() + { + int valve = (int)Valve; + TechValve = await Services.TechComponentsService.Valves.FindOne(x => x.Code == valve); + + if (TechValve != null) + { + State = (ValveStateCode)Enum.Parse(typeof(ValveStateCode), TechValve.State1.Replace(" ", ""), true); + } + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + var valveState = package.GetValveState(Valve); + + if (valveState != null) + { + EffectiveState = valveState.State; + } + } + + public override FrameworkElement GetView() + { + return new ValveWidgetView(); + } + + #region Component Selection + + public List<DiagnosticsWidgetComponent<TechValves>> Components + { + get + { + return Services.TechComponentsService.Valves.FindAll().Result.Select(x => new DiagnosticsWidgetComponent<TechValves>() + { + DisplayName = x.Description, + Object = (TechValves)x.Code, + }).OrderByAlphaNumeric(x => x.DisplayName).ToList(); + } + } + + public TechValves SelectedComponent + { + get + { + return Valve; + } + set + { + if (Valve != value) + { + Valve = value; + InitAsync(); + } + } + } + + public bool EnableComponentSelection { get; set; } + + #endregion + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml new file mode 100644 index 000000000..0ef9acbbe --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml @@ -0,0 +1,111 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Valve.ValveWidgetView" + 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.FSE.Diagnostics.Project.Widgets.Valve" + xmlns:localConverters="clr-namespace:Tango.FSE.Diagnostics.Converters" + mc:Ignorable="d" + d:DesignHeight="250" d:DesignWidth="400" d:DataContext="{d:DesignInstance Type=local:ValveWidget,IsDesignTimeCreatable=False}"> + + <UserControl.Resources> + <localConverters:ValveStateComparerToBooleanConverter x:Key="ValveStateComparerToBooleanConverter" /> + </UserControl.Resources> + + <Grid> + <Viewbox Stretch="Uniform"> + <Border Width="352" Height="101" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" CornerRadius="5" BorderThickness="1" BorderBrush="#434343" Padding="5"> + <Grid> + <Grid Grid.Row="1"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="27*"/> + <ColumnDefinition Width="30*"/> + <ColumnDefinition Width="27*"/> + </Grid.ColumnDefinitions> + + <Button Margin="8" Cursor="Hand" Command="{Binding SetCommand}" CommandParameter="{Binding TechValve.State1}"> + <Button.Style> + <Style TargetType="Button"> + <Setter Property="Background" Value="#3E3E3E"></Setter> + <Setter Property="IsEnabled" Value="True"></Setter> + </Style> + </Button.Style> + <Button.Template> + <ControlTemplate TargetType="Button"> + <Border Background="{TemplateBinding Background}" CornerRadius="5"> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gainsboro" FontSize="16" FontWeight="SemiBold" Text="{Binding TechValve.State1}"></TextBlock> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Opacity" Value="0.7"></Setter> + </Trigger> + <DataTrigger> + <DataTrigger.Binding> + <MultiBinding Converter="{StaticResource ValveStateComparerToBooleanConverter}"> + <Binding Path="State" /> + <Binding Path="TechValve.State1" /> + </MultiBinding> + </DataTrigger.Binding> + <DataTrigger.Value> + True + </DataTrigger.Value> + + <DataTrigger.Setters> + <Setter Property="Background" Value="#4AAB2F"></Setter> + <Setter Property="IsEnabled" Value="False"></Setter> + </DataTrigger.Setters> + </DataTrigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Button.Template> + </Button> + + <Border Background="{StaticResource FSE_PrimaryBackgroundBrush}" Margin="8" CornerRadius="3" Padding="5" Grid.Column="1"> + <StackPanel> + <TextBlock FontFamily="{StaticResource digital-7}" Text="Valve Controller" FontSize="13" Foreground="#E94A4A" HorizontalAlignment="Center"></TextBlock> + <Image Source="../Valve/Images/valve.png" RenderOptions.BitmapScalingMode="Fant" Margin="10" Stretch="Uniform" Height="36" /> + </StackPanel> + </Border> + + <Button Margin="8" Cursor="Hand" Grid.Column="2" Command="{Binding SetCommand}" CommandParameter="{Binding TechValve.State2}"> + <Button.Style> + <Style TargetType="Button"> + <Setter Property="Background" Value="#3E3E3E"></Setter> + <Setter Property="IsEnabled" Value="True"></Setter> + </Style> + </Button.Style> + <Button.Template> + <ControlTemplate TargetType="Button"> + <Border Background="{TemplateBinding Background}" CornerRadius="5"> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gainsboro" FontSize="16" FontWeight="SemiBold" Text="{Binding TechValve.State2}"></TextBlock> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Opacity" Value="0.7"></Setter> + </Trigger> + <DataTrigger> + <DataTrigger.Binding> + <MultiBinding Converter="{StaticResource ValveStateComparerToBooleanConverter}"> + <Binding Path="State" /> + <Binding Path="TechValve.State2" /> + </MultiBinding> + </DataTrigger.Binding> + <DataTrigger.Value> + True + </DataTrigger.Value> + + <DataTrigger.Setters> + <Setter Property="Background" Value="#4AAB2F"></Setter> + <Setter Property="IsEnabled" Value="False"></Setter> + </DataTrigger.Setters> + </DataTrigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Button.Template> + </Button> + </Grid> + </Grid> + </Border> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml.cs new file mode 100644 index 000000000..cdaf5a324 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Valve/ValveWidgetView.xaml.cs @@ -0,0 +1,28 @@ +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.FSE.Diagnostics.Project.Widgets.Valve +{ + /// <summary> + /// Interaction logic for ValveWidgetView.xaml + /// </summary> + public partial class ValveWidgetView : UserControl + { + public ValveWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj index 2b3699858..a61ddbd2d 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj @@ -63,6 +63,15 @@ <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> <Reference Include="System.Drawing" /> + <Reference Include="System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll</HintPath> + </Reference> + <Reference Include="System.Reactive.Interfaces, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll</HintPath> + </Reference> + <Reference Include="System.Reactive.Linq, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\System.Reactive.Linq.3.1.1\lib\net46\System.Reactive.Linq.dll</HintPath> + </Reference> <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll</HintPath> </Reference> @@ -81,18 +90,45 @@ </ItemGroup> <ItemGroup> <Compile Include="Controls\DiagnosticsGrid.cs" /> + <Compile Include="Controls\DiagnosticsGridLinesEditor.xaml.cs"> + <DependentUpon>DiagnosticsGridLinesEditor.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\DiagnosticsSelectionGrid.cs" /> <Compile Include="Converters\DecimalPlacesToStringFormatConverter.cs" /> <Compile Include="Converters\DiagnosticsWidgetToSettingsViewConverter.cs" /> <Compile Include="Converters\DiagnosticsWidgetToViewConverter.cs" /> <Compile Include="Converters\PercentageToWidthConverter.cs" /> + <Compile Include="Converters\ValveStateComparerToBooleanConverter.cs" /> <Compile Include="DiagnosticsPackage.cs" /> + <Compile Include="DiagnosticsSettings.cs" /> <Compile Include="Project\DiagnosticsConfigurableWidget.cs" /> <Compile Include="Project\DiagnosticsProject.cs" /> <Compile Include="Project\DiagnosticsProjectTab.cs" /> <Compile Include="Project\DiagnosticsProjectTabColumnDefinition.cs" /> <Compile Include="Project\DiagnosticsProjectTabRowDefinition.cs" /> + <Compile Include="Project\DiagnosticsUserSettingsCollection.cs" /> + <Compile Include="Project\DiagnosticsUserSettingsManager.cs" /> + <Compile Include="Project\DiagnosticsUserWidgetSettings.cs" /> <Compile Include="Project\DiagnosticsWidget.cs" /> + <Compile Include="Project\DiagnosticsWidgetComponent.cs" /> <Compile Include="Project\DiagnosticsWidgetSettings.cs" /> + <Compile Include="Project\ISupportsComponentSelection.cs" /> + <Compile Include="Project\Widgets\Dispenser\DispenserWidget.cs" /> + <Compile Include="Project\Widgets\Dispenser\DispenserWidgetSettings.cs" /> + <Compile Include="Project\Widgets\Dispenser\DispenserWidgetSettingsView.xaml.cs"> + <DependentUpon>DispenserWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Dispenser\DispenserWidgetView.xaml.cs"> + <DependentUpon>DispenserWidgetView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Heater\HeaterWidget.cs" /> + <Compile Include="Project\Widgets\Heater\HeaterWidgetView.xaml.cs"> + <DependentUpon>HeaterWidgetView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Input\InputWidget.cs" /> + <Compile Include="Project\Widgets\Input\InputWidgetView.xaml.cs"> + <DependentUpon>InputWidgetView.xaml</DependentUpon> + </Compile> <Compile Include="Project\Widgets\Monitor\MonitorWidget.cs" /> <Compile Include="Project\Widgets\Monitor\MonitorWidgetSettings.cs" /> <Compile Include="Project\Widgets\Monitor\MonitorWidgetSettingsView.xaml.cs"> @@ -101,6 +137,15 @@ <Compile Include="Project\Widgets\Monitor\MonitorWidgetView.xaml.cs"> <DependentUpon>MonitorWidgetView.xaml</DependentUpon> </Compile> + <Compile Include="Project\Widgets\Motor\MotorWidget.cs" /> + <Compile Include="Project\Widgets\Motor\MotorWidgetSettings.cs" /> + <Compile Include="Project\Widgets\Motor\MotorWidgetSettingsView.xaml.cs"> + <DependentUpon>MotorWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Motor\MotorWidgetState.cs" /> + <Compile Include="Project\Widgets\Motor\MotorWidgetView.xaml.cs"> + <DependentUpon>MotorWidgetView.xaml</DependentUpon> + </Compile> <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidget.cs" /> <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetSettingsView.xaml.cs"> <DependentUpon>RealTimeGraphMultiChannelWidgetSettingsView.xaml</DependentUpon> @@ -118,6 +163,18 @@ <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetView.xaml.cs"> <DependentUpon>RealTimeGraphWidgetView.xaml</DependentUpon> </Compile> + <Compile Include="Project\Widgets\Text\TextWidget.cs" /> + <Compile Include="Project\Widgets\Text\TextWidgetSettings.cs" /> + <Compile Include="Project\Widgets\Text\TextWidgetSettingsView.xaml.cs"> + <DependentUpon>TextWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Text\TextWidgetView.xaml.cs"> + <DependentUpon>TextWidgetView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Valve\ValveWidget.cs" /> + <Compile Include="Project\Widgets\Valve\ValveWidgetView.xaml.cs"> + <DependentUpon>ValveWidgetView.xaml</DependentUpon> + </Compile> <Compile Include="ViewModelLocator.cs" /> <Compile Include="DiagnosticsModule.cs" /> <Compile Include="ViewModels\DiagnosticsTabViewVM.cs" /> @@ -155,7 +212,7 @@ <SubType>Designer</SubType> </None> <None Include="diagnostics.json"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> <None Include="packages.config" /> <None Include="Properties\Settings.settings"> @@ -212,6 +269,10 @@ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> <Name>Tango.Transport</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Visuals\Tango.Visuals.csproj"> + <Project>{cf7c0ff4-9440-42cf-83b8-c060772792d4}</Project> + <Name>Tango.Visuals</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.FSE.BL\Tango.FSE.BL.csproj"> <Project>{834c81c3-09b5-45d7-be12-e7d1e6655a7c}</Project> <Name>Tango.FSE.BL</Name> @@ -226,6 +287,26 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Controls\DiagnosticsGridLinesEditor.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Dispenser\DispenserWidgetSettingsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Dispenser\DispenserWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Heater\HeaterWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Input\InputWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Project\Widgets\Monitor\MonitorWidgetSettingsView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -234,6 +315,14 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Project\Widgets\Motor\MotorWidgetSettingsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Motor\MotorWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetView.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> @@ -250,6 +339,18 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Project\Widgets\Text\TextWidgetSettingsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Text\TextWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Valve\ValveWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Themes\Generic.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -273,6 +374,15 @@ <ItemGroup> <Resource Include="Project\Widgets\Monitor\Images\tft_screen.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Project\Widgets\Valve\Images\valve.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Project\Widgets\Dispenser\Images\dispenser_line.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Project\Widgets\Heater\Images\temperature.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml index 2428e9255..ebc71072a 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml @@ -3,29 +3,44 @@ xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" xmlns:localConverters="clr-namespace:Tango.FSE.Diagnostics.Converters" xmlns:realTimeGraphX="clr-namespace:RealTimeGraphX.WPF;assembly=RealTimeGraphX.WPF" + xmlns:commonControls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Themes"> <localConverters:DecimalPlacesToStringFormatConverter x:Key="DecimalPlacesToStringFormatConverter" /> <Style TargetType="{x:Type graphs:RealTimeGraph}" x:Key="FSE_RealTimeGraph_Diagnostics"> <Setter Property="BorderThickness" Value="1"></Setter> - <Setter Property="BorderBrush" Value="{StaticResource FSE_RealTimeGraph_OuterBorderBrush}"></Setter> - <Setter Property="Padding" Value="20 20 30 20"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="Padding" Value="20"></Setter> <Setter Property="FontSize" Value="11"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_RealTimeGraph_ForegroundBrush}"></Setter> - <Setter Property="Background" Value="{StaticResource FSE_RealTimeGraph_BackgroundBrush}"></Setter> - <Setter Property="GridLinesBrush" Value="{StaticResource FSE_RealTimeGraph_GridLinesBrush}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" > + <GradientStop Color="#252525"/> + <GradientStop Color="#303030" Offset="1"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + <Setter Property="GridLinesBrush" Value="#282828"></Setter> <Setter Property="HorizontalTicks" Value="7"></Setter> <Setter Property="VerticalTicks" Value="5"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type graphs:RealTimeGraph}"> <Grid> - <Border Background="{TemplateBinding Background}" + <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Padding="{TemplateBinding Padding}"> + <Border.Background> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" > + <GradientStop Color="#252525"/> + <GradientStop Color="#303030" Offset="1"/> + </LinearGradientBrush> + </Border.Background> <Grid> <Grid.RowDefinitions> <RowDefinition Height="1*"/> @@ -37,12 +52,12 @@ </Grid.ColumnDefinitions> <Grid Grid.Column="1"> - <realTimeGraphX:WpfGraphGridLines Columns="{TemplateBinding HorizontalTicks}" Rows="{TemplateBinding VerticalTicks}" Controller="{TemplateBinding Controller}" Foreground="{TemplateBinding GridLinesBrush}" /> - <realTimeGraphX:WpfGraphSurface x:Name="surface" Controller="{TemplateBinding Controller}" BorderThickness="1 0 0 1" BorderBrush="{StaticResource FSE_RealTimeGraph_InnerBorderBrush}" /> + <realTimeGraphX:WpfGraphSurface x:Name="surface" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Controller="{TemplateBinding Controller}" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" /> + <realTimeGraphX:WpfGraphGridLines Columns="{TemplateBinding HorizontalTicks}" Rows="{TemplateBinding VerticalTicks}" Controller="{TemplateBinding Controller}" Foreground="{TemplateBinding GridLinesBrush}" Margin="1 0 0 1" /> </Grid> - <realTimeGraphX:WpfGraphAxisControl Width="70" Visibility="{TemplateBinding VerticalAxisVisibility}" Orientation="Vertical" Controller="{TemplateBinding Controller}" StringFormat="{TemplateBinding StringFormat}" Ticks="{TemplateBinding VerticalTicks}" /> - <realTimeGraphX:WpfGraphAxisControl Height="35" Visibility="{TemplateBinding HorizontalAxisVisibility}" Orientation="Horizontal" Controller="{TemplateBinding Controller}" Grid.Column="1" Grid.Row="1" Ticks="{TemplateBinding HorizontalTicks}" StringFormat="hh\:mm\:ss"/> + <realTimeGraphX:WpfGraphAxisControl Width="50" Visibility="{TemplateBinding VerticalAxisVisibility}" Orientation="Vertical" Controller="{TemplateBinding Controller}" StringFormat="{TemplateBinding StringFormat}" Ticks="{TemplateBinding VerticalTicks}" /> + <realTimeGraphX:WpfGraphAxisControl Height="30" Visibility="{TemplateBinding HorizontalAxisVisibility}" Orientation="Horizontal" Controller="{TemplateBinding Controller}" Grid.Column="1" Grid.Row="1" Ticks="{TemplateBinding HorizontalTicks}" StringFormat="hh\:mm\:ss"/> </Grid> </Border> <Image HorizontalAlignment="Left" VerticalAlignment="Top" Margin="8" Source="{StaticResource FSE_Screw}" RenderOptions.BitmapScalingMode="Fant" Width="10" Height="10" /> @@ -56,5 +71,118 @@ </Setter> </Style> - + <Color x:Key="FSE_Widget_Gradient_Dark_Color">#232323</Color> + <Color x:Key="FSE_Widget_Gradient_Mid_Color">#FF333333</Color> + <Color x:Key="FSE_Widget_Gradient_Light_Color">#FF646464</Color> + + <Style x:Key="FSE_WidgetIconButton_Red" TargetType="{x:Type commonControls:IconButton}" BasedOn="{StaticResource FSE_IconButton_Flat_Pressed_Highlight}"> + <Style.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_RedBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + + <Style x:Key="FSE_MotorWidgetButton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> + <Setter Property="Padding" Value="0"></Setter> + <Setter Property="Width" Value="Auto"></Setter> + <Setter Property="Height" Value="Auto"></Setter> + <Setter Property="material:RippleAssist.IsDisabled" Value="True"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_BorderBrush}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="1,0"> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Light_Color}" Offset="0" /> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Dark_Color}" Offset="1"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + <Style.Triggers> + <EventTrigger RoutedEvent="PreviewMouseDown"> + <EventTrigger.Actions> + <BeginStoryboard> + <Storyboard> + <ColorAnimation Storyboard.TargetProperty="Background.GradientStops[0].Color" To="{StaticResource FSE_Widget_Gradient_Mid_Color}" Duration="00:00:0.1" /> + </Storyboard> + </BeginStoryboard> + </EventTrigger.Actions> + </EventTrigger> + <EventTrigger RoutedEvent="PreviewMouseUp"> + <EventTrigger.Actions> + <BeginStoryboard> + <Storyboard> + <ColorAnimation Storyboard.TargetProperty="Background.GradientStops[0].Color" To="{StaticResource FSE_Widget_Gradient_Light_Color}" Duration="00:00:0.1" /> + </Storyboard> + </BeginStoryboard> + </EventTrigger.Actions> + </EventTrigger> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + </Trigger> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_RedBrush}"></Setter> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + + <Style x:Key="FSE_MotorWidgetButton_Left" TargetType="Button" BasedOn="{StaticResource FSE_MotorWidgetButton}"> + <Setter Property="BorderThickness" Value="1 1 0 1"></Setter> + <Setter Property="material:ButtonAssist.CornerRadius" Value="10 0 0 10"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="1,0"> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Light_Color}" Offset="1" /> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Dark_Color}" Offset="0"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="FSE_MotorWidgetButton_Right" TargetType="Button" BasedOn="{StaticResource FSE_MotorWidgetButton}"> + <Setter Property="BorderThickness" Value="0 1 1 1"></Setter> + <Setter Property="material:ButtonAssist.CornerRadius" Value="0 10 10 0"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="1,0"> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Light_Color}" Offset="0" /> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Dark_Color}" Offset="1"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="FSE_MotorWidgetButton_Center" TargetType="Button" BasedOn="{StaticResource FSE_MotorWidgetButton}"> + <Setter Property="BorderThickness" Value="1 0 1 1"></Setter> + <Setter Property="material:ButtonAssist.CornerRadius" Value="0 0 20 20"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Light_Color}" Offset="0" /> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Dark_Color}" Offset="1"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="FSE_MotorWidgetBorder_Center" TargetType="Border"> + <Setter Property="Padding" Value="0"></Setter> + <Setter Property="Width" Value="Auto"></Setter> + <Setter Property="Height" Value="Auto"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_BorderBrush}"></Setter> + <Setter Property="BorderThickness" Value="1 0 1 1"></Setter> + <Setter Property="CornerRadius" Value="0 0 20 20"></Setter> + <Setter Property="Background"> + <Setter.Value> + <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Dark_Color}" Offset="1" /> + <GradientStop Color="{StaticResource FSE_Widget_Gradient_Light_Color}" Offset="0"/> + </LinearGradientBrush> + </Setter.Value> + </Setter> + </Style> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs index acea47b10..0acfa2a4f 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs @@ -3,20 +3,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; using Tango.Core.Commands; +using Tango.Core.DI; using Tango.FSE.Common; +using Tango.FSE.Common.Authentication; using Tango.FSE.Diagnostics.Project; using Tango.PMR.Diagnostics; +using Tango.Settings; namespace Tango.FSE.Diagnostics.ViewModels { - public class DiagnosticsTabViewVM : FSEViewModel + public class DiagnosticsTabViewVM : FSEViewModelWithModuleSettings<DiagnosticsSettings> { private DiagnosticsProjectTab _tab; public DiagnosticsProjectTab Tab { get { return _tab; } - set { _tab = value; RaisePropertyChangedAuto(); } + set { _tab = value; RaisePropertyChangedAuto(); OnTabChanged(); } } private bool _isSelected; @@ -40,6 +44,20 @@ namespace Tango.FSE.Diagnostics.ViewModels set { _isWidgetSettingsOpened = value; RaisePropertyChangedAuto(); } } + private bool _editMode; + public bool EditMode + { + get { return _editMode; } + set { _editMode = value; RaisePropertyChangedAuto(); Tab.Widgets.ToList().ForEach(x => x.EditMode = value); } + } + + private bool _showGridLines; + public bool ShowGridLines + { + get { return _showGridLines; } + set { _showGridLines = value; RaisePropertyChangedAuto(); } + } + public RelayCommand<DiagnosticsWidget> OpenWidgetSettingsCommand { get; set; } public RelayCommand CloseWidgetSettingsCommand { get; set; } @@ -47,7 +65,7 @@ namespace Tango.FSE.Diagnostics.ViewModels public DiagnosticsTabViewVM() { OpenWidgetSettingsCommand = new RelayCommand<DiagnosticsWidget>(OpenWidgetSettings); - CloseWidgetSettingsCommand = new RelayCommand(() => IsWidgetSettingsOpened = false); + CloseWidgetSettingsCommand = new RelayCommand(() => { IsWidgetSettingsOpened = false; SelectedWidget = null; }); } private void OpenWidgetSettings(DiagnosticsWidget widget) @@ -67,5 +85,18 @@ namespace Tango.FSE.Diagnostics.ViewModels widget.OnDiagnosticsData(package); } } + + private void OnTabChanged() + { + if (Tab != null) + { + Tab.Widgets.CollectionChanged += Widgets_CollectionChanged; + } + } + + private void Widgets_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + Tab.Widgets.ToList().ForEach(x => x.EditMode = EditMode); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs index 75c623c62..17b9391c9 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs @@ -1,14 +1,19 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.FSE.Common; using Tango.FSE.Common.Diagnostics; +using Tango.FSE.Common.Notifications; using Tango.FSE.Diagnostics.Project; using Tango.PMR.Diagnostics; @@ -16,10 +21,24 @@ namespace Tango.FSE.Diagnostics.ViewModels { public class DiagnosticsViewVM : FSEViewModel { - private Dictionary<String, PropertyInfo> _monitorsProperties; + public class WidgetType + { + public String Name { get; set; } + public Type Type { get; set; } + + public override string ToString() + { + return Name; + } + } + private bool _isLoaded; - private string _diagnosticsProjectFile; + private string _factoryPojectFile; + private string _customProjectFile; private FileSystemWatcher _diagnosticsProjectFileWatcher; + private List<DiagnosticsWidget> _copiedWidget; + + #region Properties private bool _isLoadingProject; public bool IsLoadingProject @@ -49,23 +68,265 @@ namespace Tango.FSE.Diagnostics.ViewModels set { _selectedTab = value; RaisePropertyChangedAuto(); OnSelectedTabChanged(); } } - public RelayCommand ExportProjectCommand { get; set; } + public List<WidgetType> AvailableWidgetTypes { get; set; } - public DiagnosticsViewVM() + private WidgetType _selectedWidgetType; + public WidgetType SelectedWidgetType + { + get { return _selectedWidgetType; } + set { _selectedWidgetType = value; RaisePropertyChangedAuto(); } + } + + private bool _editMode; + public bool EditMode + { + get { return _editMode; } + set { _editMode = value; RaisePropertyChangedAuto(); OnEditModeChanged(); } + } + + private bool _creationMode; + public bool CreationMode + { + get { return _creationMode; } + set { _creationMode = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(NotInCreationOrPasteMode)); InvalidateRelayCommands(); } + } + + private bool _pasteMode; + public bool PasteMode { - _monitorsProperties = new Dictionary<string, PropertyInfo>(); + get { return _pasteMode; } + set { _pasteMode = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(NotInCreationOrPasteMode)); InvalidateRelayCommands(); } + } - foreach (var prop in typeof(DiagnosticsMonitors).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList()) + public bool NotInCreationOrPasteMode + { + get { return !CreationMode && !PasteMode; } + } + + private bool _showGridLines; + public bool ShowGridLines + { + get { return _showGridLines; } + set { - _monitorsProperties.Add(prop.Name, prop); + _showGridLines = value; + RaisePropertyChangedAuto(); + Tabs.ToList().ForEach(x => x.ShowGridLines = value); } + } + + #endregion + + #region Commands + + public RelayCommand NewProjectCommand { get; set; } + public RelayCommand OpenProjectCommand { get; set; } + public RelayCommand SaveProjectCommand { get; set; } + public RelayCommand SaveAsProjectCommand { get; set; } + public RelayCommand CutSelectedWidgetsCommand { get; set; } + public RelayCommand CopySelectedWidgetsCommand { get; set; } + public RelayCommand PasteWidgetsCommand { get; set; } + public RelayCommand DeleteSelectedWidgetsCommand { get; set; } + public RelayCommand AddNewTabCommand { get; set; } + public RelayCommand<DiagnosticsTabViewVM> RemoveTabCommand { get; set; } + public RelayCommand<WidgetType> AddWidgetCommand { get; set; } + public RelayCommand<Rect> SelectionCommand { get; set; } + public RelayCommand AbortCreationCommand { get; set; } + public RelayCommand DeselectWidgetsCommand { get; set; } + public RelayCommand ResetGridCommand { get; set; } + #endregion + + #region Constructors + + public DiagnosticsViewVM() + { Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); Project = new DiagnosticsProject(); + AvailableWidgetTypes = new List<WidgetType>(); - ExportProjectCommand = new RelayCommand(ExportProject); + _copiedWidget = new List<DiagnosticsWidget>(); + + OpenProjectCommand = new RelayCommand(OpenProject, () => EditMode); + SaveProjectCommand = new RelayCommand(SaveProject, () => EditMode); + SaveAsProjectCommand = new RelayCommand(SaveAsProject, () => EditMode); + NewProjectCommand = new RelayCommand(CreateNewProject, () => EditMode); + AddNewTabCommand = new RelayCommand(AddNewTab, () => EditMode); + RemoveTabCommand = new RelayCommand<DiagnosticsTabViewVM>(RemoveTab, () => EditMode); + AddWidgetCommand = new RelayCommand<WidgetType>(StartWidgetCreation, () => EditMode && SelectedTab != null); + SelectionCommand = new RelayCommand<Rect>(OnWidgetCreation, () => EditMode && ((CreationMode && SelectedWidgetType != null) || PasteMode) && SelectedTab != null); + AbortCreationCommand = new RelayCommand(AbortWidgetCreation, () => EditMode && (CreationMode || PasteMode)); + DeselectWidgetsCommand = new RelayCommand(DeselectAllWidgets, () => EditMode); + CopySelectedWidgetsCommand = new RelayCommand(CopySelectedWidgets, () => EditMode && SelectedTab != null && SelectedTab.Tab.Widgets.Any(x => x.IsSelected)); + PasteWidgetsCommand = new RelayCommand(StartPasteWidgets, () => EditMode && !PasteMode && !CreationMode && _copiedWidget.Count > 0); + ResetGridCommand = new RelayCommand(ResetSelectedTabGrid, () => EditMode && SelectedTab != null); + DeleteSelectedWidgetsCommand = new RelayCommand(DeleteSelectedWidgets, () => EditMode && SelectedTab != null && SelectedTab.Tab.Widgets.Any(x => x.IsSelected)); + CutSelectedWidgetsCommand = new RelayCommand(CutSelectedWidgets, () => EditMode && SelectedTab != null && SelectedTab.Tab.Widgets.Any(x => x.IsSelected)); + + InitAvailableWidgetTypes(); } + #endregion + + #region Widget Management + + private void InitAvailableWidgetTypes() + { + var types = this.GetType().Assembly.GetTypes().Where(x => typeof(DiagnosticsWidget).IsAssignableFrom(x) && !x.IsAbstract).ToList(); + + foreach (var type in types.OrderBy(x => x.Name).ToList()) + { + var att = type.GetCustomAttribute<DescriptionAttribute>(); + + AvailableWidgetTypes.Add(new WidgetType() + { + Name = att != null ? att.Description : type.Name.Replace("Widget", ""), + Type = type + }); + } + } + + private void StartWidgetCreation(WidgetType widgetType) + { + if (SelectedTab == null || PasteMode) return; + + DeselectAllWidgets(); + SelectedWidgetType = widgetType; + CreationMode = true; + } + + private void AbortWidgetCreation() + { + CreationMode = false; + PasteMode = false; + SelectedWidgetType = null; + } + + private async void OnWidgetCreation(Rect rect) + { + if (CreationMode) + { + CreationMode = false; + + if (SelectedTab == null || SelectedWidgetType == null) return; + + DiagnosticsWidget widget = Activator.CreateInstance(SelectedWidgetType.Type) as DiagnosticsWidget; + widget.Column = (int)rect.X; + widget.Row = (int)rect.Y; + widget.ColumnSpan = (int)rect.Width; + widget.RowSpan = (int)rect.Height; + + await AddWidget(SelectedTab.Tab, widget); + + SelectedWidgetType = null; + } + else if (PasteMode && _copiedWidget.Count > 0) + { + PasteMode = false; + + if (SelectedTab == null) return; + + var startLeft = _copiedWidget.Min(x => x.Column); + var startTop = _copiedWidget.Min(x => x.Row); + var offsetX = rect.Left - startLeft; + var offsetY = rect.Top - startTop; + + foreach (var widget in _copiedWidget.Select(x => x.Clone()).ToList()) + { + widget.Column += (int)offsetX; + widget.Row += (int)offsetY; + await AddWidget(SelectedTab.Tab, widget); + } + } + } + + private async Task AddWidget(DiagnosticsProjectTab tab, DiagnosticsWidget widget) + { + await widget.Init(); + tab.Widgets.Add(widget); + } + + private Rect? GetFirstAvailableTabSpace(DiagnosticsProjectTab tab, int columnSpan, int rowSpan) + { + int column = 0; + int row = 0; + + List<Rect> board = tab.Widgets.Select(x => new Rect(x.Column, x.Row, Math.Max(x.ColumnSpan, 1), Math.Max(x.RowSpan, 1))).ToList(); + + bool found = false; + + //Search for first available space by intersection. + for (int rowIndex = 0; rowIndex < tab.Rows.Count; rowIndex++) + { + for (int columnIndex = 0; columnIndex < tab.Columns.Count; columnIndex++) + { + Rect rect = new Rect(columnIndex, rowIndex, columnSpan, rowSpan); + + if (board.Any(x => + { + var intersect = Rect.Intersect(x, rect); + return (intersect.Width > 0 && intersect.Height > 0); + })) + { + continue; + } + + column = columnIndex; + row = rowIndex; + found = true; + break; + } + + if (found) break; + } + + if (found) + { + return new Rect(column, row, columnSpan, rowSpan); + } + + return null; + } + + private void DisposeWidgets(IEnumerable<DiagnosticsWidget> widgets) + { + foreach (var widget in widgets.ToList()) + { + try + { + widget.Dispose(); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error disposing widget {widget.DisplayName}, {widget.ID}."); + } + } + } + + private void DeleteSelectedWidgets() + { + if (SelectedTab != null && SelectedTab.Tab.Widgets.Count(x => x.IsSelected) > 0) + { + var selectedWidgets = SelectedTab.Tab.Widgets.Where(x => x.IsSelected).ToList(); + + foreach (var widget in selectedWidgets) + { + SelectedTab.Tab.Widgets.Remove(widget); + widget.Dispose(); + } + } + } + + private void CutSelectedWidgets() + { + CopySelectedWidgets(); + DeleteSelectedWidgets(); + } + + #endregion + + #region Override Methods + public override void OnApplicationStarted() { base.OnApplicationStarted(); @@ -76,6 +337,28 @@ namespace Tango.FSE.Diagnostics.ViewModels _diagnosticsProjectFileWatcher.EnableRaisingEvents = true; } + public async override void OnApplicationReady() + { + base.OnApplicationReady(); + + if (!_isLoaded) + { + _factoryPojectFile = Path.Combine(ApplicationManager.StartPath, "diagnostics.json"); + await LoadProject(); + } + } + + public override void OnApplicationShuttingDown() + { + base.OnApplicationShuttingDown(); + + SaveUserSettings(); + } + + #endregion + + #region File System Watcher + private void _diagnosticsProjectFileWatcher_Changed(object sender, FileSystemEventArgs e) { InvokeUI(async () => @@ -97,37 +380,70 @@ namespace Tango.FSE.Diagnostics.ViewModels }); } + #endregion + + #region Diagnostics Frame Received + private void DiagnosticsProvider_FrameReceived(object sender, DiagnosticsFrameReceivedEventArgs e) { PopulateDiagnosticsData(e.Frame); } - public async override void OnApplicationReady() + #endregion + + #region Project Management + + private async void OpenProject() { - base.OnApplicationReady(); + var result = await StorageProvider.OpenFile("Open diagnostics project", "Diagnostics Projects|*.json"); - if (!_isLoaded) + if (result.Confirmed) { - _diagnosticsProjectFile = Path.Combine(ApplicationManager.StartPath, "diagnostics.json"); - await LoadProject(); + try + { + await LoadProject(result.SelectedItem, true); + _customProjectFile = result.SelectedItem; + } + catch (Exception ex) + { + await NotificationProvider.ShowError($"Error opening diagnostics project.\n{ex.FlattenMessage()}"); + } } } - private async Task LoadProject() + private Task LoadProject() { - Project = DiagnosticsProject.FromFile(_diagnosticsProjectFile); + return LoadProject(_factoryPojectFile); + } + private async Task LoadProject(String filePath, bool throwException = false) + { try { IsLoadingProject = true; _isLoaded = false; + if (Project != null) + { + DisposeWidgets(Project.FlattenWidgets()); + } + + Project = DiagnosticsProject.FromFile(filePath); + await Services.TechComponentsService.Preload(); foreach (var widget in Project.Tabs.SelectMany(x => x.Widgets)) { try { + if (widget is DiagnosticsConfigurableWidget) + { + await Task.Factory.StartNew(() => + { + DiagnosticsUserSettingsManager.Default.Settings.ApplyWidgetSettings(widget as DiagnosticsConfigurableWidget); + }); + } + await widget.Init(); } catch (Exception ex) @@ -149,7 +465,10 @@ namespace Tango.FSE.Diagnostics.ViewModels catch (Exception ex) { NotificationProvider.PushErrorReportingSnackbar(ex, "Diagnostics Module Error", "Error initializing diagnostics module."); - return; + if (throwException) + { + throw ex; + } } finally { @@ -157,11 +476,172 @@ namespace Tango.FSE.Diagnostics.ViewModels } } + private async void SaveAsProject() + { + var result = await StorageProvider.SaveFile("Save diagnostics project", "Diagnostics Projects|*.json", "diagnostics.json", ".json"); + + if (result.Confirmed) + { + SaveProject(result.SelectedItem); + } + } + + private void SaveProject() + { + if (_customProjectFile != null) + { + SaveProject(_customProjectFile); + } + else + { + SaveAsProject(); + } + } + + private void SaveProject(String filePath, bool throwException = false) + { + try + { + Project.ToFile(filePath); + SaveUserSettings(); + _customProjectFile = filePath; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving diagnostics project."); + NotificationProvider.ShowError($"Error saving diagnostics project.\n{ex.FlattenMessage()}"); + + if (throwException) + { + throw ex; + } + } + } + + private async void CreateNewProject() + { + if (!await NotificationProvider.ShowWarningQuestion("Are you sure you want to create a new project?")) return; + + if (Project != null) + { + DisposeWidgets(Project.FlattenWidgets()); + } + + Project = new DiagnosticsProject(); + Project.Tabs.Add(DiagnosticsProjectTab.CreateNew("untitled", 12, 12)); + + Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); + foreach (var tab in Project.Tabs) + { + Tabs.Add(new DiagnosticsTabViewVM() { Tab = tab }); + } + + SelectedTab = Tabs.FirstOrDefault(); + } + + private void SaveUserSettings() + { + if (EditMode) return; + + try + { + foreach (var widget in Project.FlattenWidgets()) + { + try + { + if (widget is DiagnosticsConfigurableWidget) + { + DiagnosticsUserSettingsManager.Default.Settings.SetWidgetSettings(widget as DiagnosticsConfigurableWidget); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error saving widget user settings for widget '{widget.DisplayName}'."); + } + } + + //If you are going to work with different projects in the future you need to remote this. + //Because it will erase any settings other than for the current project. + DiagnosticsUserSettingsManager.Default.ClearGhostRecords(Project.FlattenWidgets().OfType<DiagnosticsConfigurableWidget>().ToList()); + + DiagnosticsUserSettingsManager.Default.Save(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving diagnostics user settings collection."); + } + } + + #endregion + + #region Tab Management + + private void ResetSelectedTabGrid() + { + if (SelectedTab != null) + { + foreach (var column in SelectedTab.Tab.Columns) + { + column.Width = new GridLength(1, GridUnitType.Star); + } + + foreach (var row in SelectedTab.Tab.Rows) + { + row.Height = new GridLength(1, GridUnitType.Star); + } + } + } + private void OnSelectedTabChanged() { } + private void AddNewTab() + { + var tab = DiagnosticsProjectTab.CreateNew("untitled", 12, 12); + var tabVM = new DiagnosticsTabViewVM() + { + Tab = tab + }; + + Project.Tabs.Add(tab); + Tabs.Add(tabVM); + + tabVM.ShowGridLines = ShowGridLines; + tabVM.EditMode = EditMode; + SelectedTab = tabVM; + } + + private async void RemoveTab(DiagnosticsTabViewVM tabVM) + { + if (await NotificationProvider.ShowWarningQuestion("Are you sure you want to remove this tab?")) + { + var index = Tabs.IndexOf(tabVM); + Tabs.Remove(tabVM); + Project.Tabs.Remove(tabVM.Tab); + DisposeWidgets(tabVM.Tab.Widgets); + + if (Tabs.Count > index) + { + SelectedTab = Tabs[index]; + } + else + { + SelectedTab = null; + } + } + } + + private void DeselectAllWidgets() + { + Tabs.ToList().ForEach(x => { x.SelectedWidget = null; x.IsWidgetSettingsOpened = false; }); + } + + #endregion + + #region Populate Diagnostics Data + private void PopulateDiagnosticsData(DiagnosticsFrame frame) { if (_isLoaded) @@ -171,28 +651,43 @@ namespace Tango.FSE.Diagnostics.ViewModels tab.PopulateDiagnosticsData(new DiagnosticsPackage() { Frame = frame, - MonitorsProperties = _monitorsProperties }); } } } - private async void ExportProject() + #endregion + + #region Properties Change + + private void OnEditModeChanged() { - var result = await StorageProvider.SaveFile("Export diagnostics project", "Diagnostics Projects|*.json", "diagnostics.json", ".json"); + Tabs.ToList().ForEach(x => x.EditMode = EditMode); + InvalidateRelayCommands(); + } - if (result.Confirmed) - { - try - { - Project.ToFile(result.SelectedItem); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error exporting diagnostics project."); - await NotificationProvider.ShowError($"Error exporting diagnostics project\n{ex.FlattenMessage()}"); - } - } + #endregion + + #region Cut / Copy /Paste + + private void CopySelectedWidgets() + { + _copiedWidget.Clear(); + var selectedWidgets = SelectedTab.Tab.Widgets.Where(x => x.IsSelected).ToList(); + _copiedWidget.AddRange(selectedWidgets.Select(x => x.Clone())); + InvalidateRelayCommands(); + + NotificationProvider.PushSnackbarItem(MessageType.Info, "Diagnostics Widgets Copied", true, $"{_copiedWidget.Count} diagnostics widgets copied.", TimeSpan.FromSeconds(1.5)); + } + + private void StartPasteWidgets() + { + if (SelectedTab == null || CreationMode) return; + + DeselectAllWidgets(); + PasteMode = true; } + + #endregion } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml index 7a8545f86..ffd8ee983 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml @@ -7,12 +7,13 @@ xmlns:commonControls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:controls="clr-namespace:Tango.FSE.Diagnostics.Controls" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" xmlns:converters="clr-namespace:Tango.FSE.Diagnostics.Converters" mc:Ignorable="d" - d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsTabViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + d:DesignHeight="720" d:DesignWidth="1280" FocusVisualStyle="{x:Null}" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsTabViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> <UserControl.Resources> <converters:DiagnosticsWidgetToViewConverter x:Key="DiagnosticsWidgetToViewConverter" /> @@ -21,10 +22,10 @@ </UserControl.Resources> <Grid> - <ListBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding Tab.Widgets}" SelectedItem="{Binding SelectedWidget,Mode=TwoWay}" Style="{StaticResource FSE_BlankListBox}" ScrollViewer.VerticalScrollBarVisibility="Disabled"> + <ListBox FocusVisualStyle="{x:Null}" SelectionMode="Extended" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding Tab.Widgets}" SelectedItem="{Binding SelectedWidget,Mode=TwoWay}" Style="{StaticResource FSE_BlankListBox}" ScrollViewer.VerticalScrollBarVisibility="Disabled"> <ListBox.ItemsPanel> <ItemsPanelTemplate> - <controls:DiagnosticsGrid IsItemsHost="True" ShowGridLines="False" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> + <controls:DiagnosticsGrid IsItemsHost="True" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemContainerStyle> @@ -33,67 +34,130 @@ <Setter Property="Grid.Row" Value="{Binding Row}"></Setter> <Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"></Setter> <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"></Setter> + <Setter Property="IsSelected" Value="{Binding IsSelected,Mode=TwoWay}"></Setter> <Setter Property="Margin" Value="5"></Setter> </Style> </ListBox.ItemContainerStyle> <ItemsControl.ItemTemplate> <DataTemplate> - <Grid x:Name="parentGrid"> - <Grid x:Name="widgetGrid" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center"> - <Grid.Width> - <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> - <Binding ElementName="parentGrid" Path="ActualWidth" /> - <Binding Path="Width" /> - </MultiBinding> - </Grid.Width> - <Grid.Height> - <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> - <Binding ElementName="parentGrid" Path="ActualHeight" /> - <Binding Path="Height" /> - </MultiBinding> - </Grid.Height> - - <ContentPresenter Content="{Binding Converter={StaticResource DiagnosticsWidgetToViewConverter}}"/> + <Grid> + <DockPanel x:Name="dockPanel"> + <Border Background="#292929" Padding="5" CornerRadius="5" DockPanel.Dock="{Binding ComponentNameAlignment}" Visibility="{Binding DisplayComponentName,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Margin" Value="0 0 0 5"></Setter> + <Setter Property="Visibility" Value="Collapsed"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding ComponentNameAlignment}" Value="Bottom"> + <Setter Property="Margin" Value="0 5 0 0"></Setter> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding DisplayName}"/> + </Border> + <Grid x:Name="parentGrid"> + <Grid x:Name="widgetGrid" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center"> + <Grid.Width> + <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> + <Binding ElementName="parentGrid" Path="ActualWidth" /> + <Binding Path="Width" /> + </MultiBinding> + </Grid.Width> + <Grid.Height> + <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> + <Binding ElementName="parentGrid" Path="ActualHeight" /> + <Binding Path="Height" /> + </MultiBinding> + </Grid.Height> - <Grid HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="32" Height="32" Margin="10" Visibility="{Binding Settings,Converter={StaticResource IsNullToVisibilityConverter},FallbackValue='Collapsed',TargetNullValue='Collapsed'}"> - <i:Interaction.Triggers> - <i:EventTrigger EventName="PreviewMouseUp"> - <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenWidgetSettingsCommand}" CommandParameter="{Binding}" /> - </i:EventTrigger> - </i:Interaction.Triggers> - <Grid Cursor="Hand" Visibility="{Binding ElementName=widgetGrid,Path=IsMouseOver,Converter={StaticResource BooleanToVisibilityConverter}}"> - <Grid.Style> - <Style TargetType="Grid"> - <Setter Property="Opacity" Value="0.6"></Setter> - <Style.Triggers> - <Trigger Property="IsMouseOver" Value="True"> - <Setter Property="Opacity" Value="1"></Setter> - </Trigger> - </Style.Triggers> - </Style> - </Grid.Style> - <Ellipse Fill="#202020"/> - <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" Kind="SettingsOutline" /> + <ContentPresenter Content="{Binding Converter={StaticResource DiagnosticsWidgetToViewConverter}}"/> + + <Canvas Width="32" Height="32" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Bottom" > + <Grid Width="32" Height="32"> + <Grid.Style> + <Style TargetType="Grid"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding HasSettings}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.EditMode}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Grid.Style> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenWidgetSettingsCommand}" CommandParameter="{Binding}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Grid Cursor="Hand" Visibility="{Binding ElementName=dockPanel,Path=IsMouseOver,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Grid.Style> + <Style TargetType="Grid"> + <Setter Property="Opacity" Value="0.6"></Setter> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Opacity" Value="1"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </Grid.Style> + <Ellipse Fill="#202020"/> + <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" Kind="SettingsOutline" /> + </Grid> + </Grid> + </Canvas> </Grid> </Grid> - </Grid> + </DockPanel> + + <Border IsHitTestVisible="False" Opacity="0.4" CornerRadius="5"> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Background" Value="Transparent"></Setter> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.EditMode}" Value="True" /> + <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="True" /> + </MultiDataTrigger.Conditions> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + </Border> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ListBox> - <Grid Margin="20" HorizontalAlignment="Right" Width="300"> + <Grid Margin="0 10 0 0" HorizontalAlignment="Right" Width="300"> <Grid.Style> <Style TargetType="Grid"> <Setter Property="Visibility" Value="Collapsed"></Setter> <Style.Triggers> - <DataTrigger Binding="{Binding IsWidgetSettingsOpened}" Value="True"> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding IsWidgetSettingsOpened}" Value="True" /> + <Condition Binding="{Binding SelectedWidget.HasSettings}" Value="True" /> + </MultiDataTrigger.Conditions> <Setter Property="Visibility" Value="Visible"></Setter> - </DataTrigger> + </MultiDataTrigger> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding IsWidgetSettingsOpened}" Value="True" /> + <Condition Binding="{Binding EditMode}" Value="True" /> + </MultiDataTrigger.Conditions> + <Setter Property="Visibility" Value="Visible"></Setter> + </MultiDataTrigger> </Style.Triggers> </Style> </Grid.Style> - <Border Background="#B1393939" CornerRadius="5"> + <Border Background="{StaticResource FSE_PrimaryBackgroundBrush}" CornerRadius="5"> <Border.Effect> <DropShadowEffect ShadowDepth="0" /> </Border.Effect> @@ -101,12 +165,73 @@ <DockPanel> <Border DockPanel.Dock="Top" Background="{StaticResource FSE_PrimaryBackgroundBrush}" CornerRadius="5 5 0 0"> <DockPanel Margin="20 10 10 10"> - <commonControls:IconButton Command="{Binding CloseWidgetSettingsCommand}" ToolTip="Close Settings" Icon="Close" DockPanel.Dock="Right" Padding="0" Width="24" Height="24"></commonControls:IconButton> + <commonControls:IconButton Cursor="Hand" Command="{Binding CloseWidgetSettingsCommand}" ToolTip="Close Settings" Icon="Close" DockPanel.Dock="Right" Padding="0" Width="24" Height="24"></commonControls:IconButton> <TextBlock VerticalAlignment="Center" Text="{Binding SelectedWidget.DisplayName,Mode=OneWay}"></TextBlock> </DockPanel> </Border> <ScrollViewer Padding="10" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"> - <ContentPresenter Content="{Binding SelectedWidget,Converter={StaticResource DiagnosticsWidgetToSettingsViewConverter}}" /> + <StackPanel> + + <StackPanel Visibility="{Binding EditMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <commonControls:FSEGroupBox Margin="0 0 0 10" Header="BOUNDS" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <UniformGrid Columns="2"> + <mahapps:NumericUpDown HasDecimals="False" Margin="0 0 10 0" Value="{Binding SelectedWidget.Column,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="{Binding Tab.Columns.Count,Mode=OneWay}" Minimum="0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Column" /> + <mahapps:NumericUpDown HasDecimals="False" Margin="10 0 0 0" Value="{Binding SelectedWidget.Row,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="{Binding Tab.Rows.Count,Mode=OneWay}" Minimum="0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Row" /> + </UniformGrid> + <UniformGrid Margin="0 10 0 0" Columns="2"> + <mahapps:NumericUpDown HasDecimals="False" Margin="0 0 10 0" Value="{Binding SelectedWidget.ColumnSpan,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="{Binding Tab.Columns.Count,Mode=OneWay}" Minimum="0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Column Span" /> + <mahapps:NumericUpDown HasDecimals="False" Margin="10 0 0 0" Value="{Binding SelectedWidget.RowSpan,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="{Binding Tab.Rows.Count,Mode=OneWay}" Minimum="0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Row Span" /> + </UniformGrid> + <UniformGrid Margin="0 10 0 0" Columns="2"> + <mahapps:NumericUpDown HasDecimals="True" Margin="0 0 10 0" Value="{Binding SelectedWidget.Width,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="100" Minimum="1" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Width (%)" /> + <mahapps:NumericUpDown HasDecimals="True" Margin="10 0 0 0" Value="{Binding SelectedWidget.Height,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Maximum="100" Minimum="1" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Height (%)" /> + </UniformGrid> + </StackPanel> + </commonControls:FSEGroupBox> + </StackPanel> + + <StackPanel Margin="0 0 0 10"> + <StackPanel.Style> + <Style TargetType="StackPanel"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding SelectedWidget.SupportsComponentSelection}" Value="True" /> + <Condition Binding="{Binding SelectedWidget.EnableComponentSelection}" Value="True" /> + </MultiDataTrigger.Conditions> + <Setter Property="Visibility" Value="Visible"></Setter> + </MultiDataTrigger> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding SelectedWidget.SupportsComponentSelection}" Value="True" /> + <Condition Binding="{Binding EditMode}" Value="True" /> + </MultiDataTrigger.Conditions> + <Setter Property="Visibility" Value="Visible"></Setter> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </StackPanel.Style> + <commonControls:FSEGroupBox Header="COMPONENT" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <ComboBox FontSize="{StaticResource FSE_SmallFontSize}" material:ComboBoxAssist.ClassicMode="True" material:ComboBoxAssist.ShowSelectedItem="True" ItemsSource="{Binding SelectedWidget.Components}" SelectedValue="{Binding SelectedWidget.SelectedComponent}" SelectedValuePath="Object" DisplayMemberPath="DisplayName"></ComboBox> + + <StackPanel Visibility="{Binding EditMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" ToolTip="Enable component selection for standard users" Margin="-2 10 0 0" IsChecked="{Binding SelectedWidget.EnableComponentSelection}" FontSize="{StaticResource FSE_SmallFontSize}">Enable Component Selection</CheckBox> + + <CheckBox Margin="-2 10 0 0" FontSize="{StaticResource FSE_SmallFontSize}" IsChecked="{Binding SelectedWidget.DisplayComponentName}">Display Component Name</CheckBox> + <ComboBox Margin="0 10 0 0" FontSize="{StaticResource FSE_SmallFontSize}" material:HintAssist.Hint="Alignment" material:HintAssist.IsFloating="True" SelectedItem="{Binding SelectedWidget.ComponentNameAlignment,Mode=TwoWay}"> + <Dock>Top</Dock> + <Dock>Bottom</Dock> + </ComboBox> + </StackPanel> + </StackPanel> + </commonControls:FSEGroupBox> + </StackPanel> + + <ContentPresenter Content="{Binding SelectedWidget,Converter={StaticResource DiagnosticsWidgetToSettingsViewConverter}}" /> + </StackPanel> </ScrollViewer> </DockPanel> </Border> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs index e3814dd79..2aecb2a91 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs @@ -12,6 +12,8 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using Tango.FSE.Diagnostics.Project; +using Tango.FSE.Diagnostics.ViewModels; namespace Tango.FSE.Diagnostics.Views { @@ -20,9 +22,22 @@ namespace Tango.FSE.Diagnostics.Views /// </summary> public partial class DiagnosticsTabView : UserControl { + private DiagnosticsTabViewVM vm; + public DiagnosticsTabView() { InitializeComponent(); + Loaded += (_, __) => vm = DataContext as DiagnosticsTabViewVM; + } + + private void CheckBox_Checked(object sender, RoutedEventArgs e) + { + vm?.SelectedWidget?.RaiseHasSettings(); + } + + private void CheckBox_Unchecked(object sender, RoutedEventArgs e) + { + vm?.SelectedWidget?.RaiseHasSettings(); } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml index 96f9e1bf0..4232c2647 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml @@ -5,122 +5,295 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Diagnostics" xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" + xmlns:auth="clr-namespace:Tango.FSE.Common.Authorization;assembly=Tango.FSE.Common" xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:localControls="clr-namespace:Tango.FSE.Diagnostics.Controls" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" mc:Ignorable="d" - d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.DiagnosticsViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - <Grid Margin="20"> - <DockPanel x:Name="dock"> - <Grid DockPanel.Dock="Top" Height="50"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="1*" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="1*" /> - </Grid.ColumnDefinitions> - <Rectangle Grid.Column="0" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> - <ListBox x:Name="listTabs" Grid.Column="1" DisplayMemberPath="Tag" ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}" SelectedIndex="0"> - <ListBox.Style> - <Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}"> - <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter> - <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"></Setter> - <Setter Property="ItemsPanel"> - <Setter.Value> + d:DesignHeight="720" d:DesignWidth="1280" FocusVisualStyle="{x:Null}" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.DiagnosticsViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" x:Name="control"> + <UserControl.InputBindings> + <KeyBinding Modifiers="Ctrl" Key="S" Command="{Binding SaveProjectCommand}" /> + <KeyBinding Modifiers="Ctrl+Shift" Key="S" Command="{Binding SaveAsProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="N" Command="{Binding NewProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="O" Command="{Binding OpenProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="X" Command="{Binding CutSelectedWidgetsCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="C" Command="{Binding CopySelectedWidgetsCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="V" Command="{Binding PasteWidgetsCommand}" /> + <KeyBinding Key="Delete" Command="{Binding DeleteSelectedWidgetsCommand}" /> + <KeyBinding Key="Esc" Command="{Binding AbortCreationCommand}" /> + </UserControl.InputBindings> + <DockPanel> + <Grid DockPanel.Dock="Top" IsEnabled="{Binding NotInCreationOrPasteMode}" Visibility="{Binding EditMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <DockPanel> + <!--<Grid DockPanel.Dock="Right"> + <StackPanel Orientation="Horizontal"> + <TextBox Width="100" material:HintAssist.Hint="Tab" material:HintAssist.IsFloating="True" Text="{Binding SelectedTab.Tab.Name}"></TextBox> + <mahapps:NumericUpDown Minimum="0" Maximum="99" Value="{Binding SelectedTab.Tab.Columns}" /> + </StackPanel> + </Grid>--> + <Menu IsMainMenu="True" Margin="50 0 0 0" VerticalAlignment="Top"> + <MenuItem Header="_File"> + <MenuItem Header="_New" MinWidth="250" Command="{Binding NewProjectCommand}" InputGestureText="Ctrl+N"> + <MenuItem.Icon> + <material:PackIcon Kind="FileDocument" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Open" Command="{Binding OpenProjectCommand}" InputGestureText="Ctrl+O"> + <MenuItem.Icon> + <material:PackIcon Kind="FileEdit" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem Header="_Save" Command="{Binding SaveProjectCommand}" InputGestureText="Ctrl+S"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentSave" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Save As" Command="{Binding SaveAsProjectCommand}" InputGestureText="Ctrl+Shift+S"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentSaveAll" /> + </MenuItem.Icon> + </MenuItem> + </MenuItem> + <MenuItem Header="_Edit"> + <MenuItem Header="_Cut" Command="{Binding CutSelectedWidgetsCommand}" InputGestureText="Ctrl+X"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentCopy" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Copy" Command="{Binding CopySelectedWidgetsCommand}" InputGestureText="Ctrl+C"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentCopy" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Paste" Command="{Binding PasteWidgetsCommand}" InputGestureText="Ctrl+V"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentPaste" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem Header="_Delete" Command="{Binding DeleteSelectedWidgetsCommand}" InputGestureText="DEL"> + <MenuItem.Icon> + <material:PackIcon Kind="Delete" /> + </MenuItem.Icon> + </MenuItem> + </MenuItem> + <MenuItem Header="_Grid"> + <MenuItem IsCheckable="True" Header="_Display Grid Lines" MinWidth="250" IsChecked="{Binding ShowGridLines}"> + <MenuItem.Icon> + <material:PackIcon Kind="Grid" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Reset Uniformity" Command="{Binding ResetGridCommand}"> + <MenuItem.Icon> + <material:PackIcon Kind="Grid" /> + </MenuItem.Icon> + </MenuItem> + </MenuItem> + <MenuItem Header="_Widgets" ItemsSource="{Binding AvailableWidgetTypes}"> + <MenuItem.ItemContainerStyle> + <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}"> + <Setter Property="Command" Value="{Binding DataContext.AddWidgetCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type MenuItem}, AncestorLevel=1}}" /> + <Setter Property="CommandParameter" Value="{Binding}"></Setter> + <Setter Property="HeaderTemplate"> + <Setter.Value> + <DataTemplate> + <Border> + <DockPanel> + <material:PackIcon Kind="Plus" /> + <ContentPresenter Margin="20 0 0 0" Content="{Binding Name}" /> + </DockPanel> + </Border> + </DataTemplate> + </Setter.Value> + </Setter> + </Style> + </MenuItem.ItemContainerStyle> + </MenuItem> + </Menu> + </DockPanel> + </Grid> + <Grid> + <Grid.Style> + <Style TargetType="Grid"> + <Setter Property="Margin" Value="20"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding EditMode}" Value="True"> + <Setter Property="Margin" Value="20 0 20 5"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Grid.Style> + <DockPanel x:Name="dock"> + <Grid DockPanel.Dock="Top" Height="50"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="1*" /> + </Grid.ColumnDefinitions> + <Rectangle Grid.Column="0" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> + <ListBox x:Name="listTabs" FocusVisualStyle="{x:Null}" Grid.Column="1" DisplayMemberPath="Tag" ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}" SelectedIndex="0"> + <ListBox.Style> + <Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}"> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"></Setter> + <Setter Property="ItemsPanel"> + <Setter.Value> + <ItemsPanelTemplate> + <UniformGrid Margin="15 0 0 0" Columns="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=Items.Count}" IsItemsHost="True"></UniformGrid> + </ItemsPanelTemplate> + </Setter.Value> + </Setter> + <Setter Property="ItemContainerStyle"> + <Setter.Value> + <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> + <Setter Property="HorizontalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundBrush}"></Setter> + <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + <Setter Property="Width" Value="200"></Setter> + <Setter Property="IsSelected" Value="{Binding IsSelected,Mode=OneWayToSource}"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="ListBoxItem"> + <Grid x:Name="grid" Margin="-15 0 0 0" Background="Transparent"> + <Viewbox Stretch="Fill"> + <Grid> + <Polygon Fill="{TemplateBinding Background}" Stretch="Fill" Points="0,30 15,0 85,0 100,30"></Polygon> + <Polygon Fill="White" Stretch="Fill" Points="0,30 15,0 85,0 100,30" IsHitTestVisible="False" Opacity="0.1"> + <Polygon.Style> + <Style TargetType="Polygon"> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsMouseOver}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Polygon.Style> + </Polygon> + <Polyline Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" Stretch="Fill" Points="0,30 15,0 85,0 100,30" /> + <Rectangle VerticalAlignment="Bottom" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" /> + </Grid> + </Viewbox> + <ContentPresenter Content="{Binding Tab.Name}" TextElement.Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" /> + <controls:IconButton Visibility="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.EditMode,Converter={StaticResource BooleanToVisibilityConverter}}" Cursor="Hand" Margin="0 0 20 0" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" VerticalAlignment="Center" HorizontalAlignment="Right" Icon="Close" Width="20" Height="20" Padding="0" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveTabCommand}" CommandParameter="{Binding}" /> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" Value="True"> + + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryAccentDarkBrush}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> + <Setter Property="FontWeight" Value="SemiBold"></Setter> + <Setter Property="Panel.ZIndex" Value="200"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="False"> + <Setter Property="Panel.ZIndex" Value="-1"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </Setter.Value> + </Setter> + </Style> + </ListBox.Style> + </ListBox> + <controls:IconButton Cursor="Hand" Command="{Binding AddNewTabCommand}" Visibility="{Binding EditMode,Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Column="2" Width="24" Height="24" Padding="0" Margin="10 0 0 0" Icon="Plus" Foreground="{StaticResource FSE_PrimaryAccentBrush}" /> + <Rectangle Margin="-50 0 0 0" Grid.Column="3" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> + </Grid> + + <Grid x:Name="grid" Background="Transparent"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseRightButtonUp"> + <i:InvokeCommandAction Command="{Binding DeselectWidgetsCommand}" /> + </i:EventTrigger> + <i:EventTrigger EventName="MouseDown"> + <i:InvokeCommandAction Command="{Binding DeselectWidgetsCommand}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Viewbox Stretch="Uniform" Margin="0 0 0 0" VerticalAlignment="Top" Width="{Binding ElementName=grid,Path=ActualWidth}" Height="{Binding ElementName=grid,Path=ActualHeight}"> + <Grid> + <ItemsControl x:Name="tabControl" Width="1810" Height="827" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> + <ItemsControl.Style> + <Style TargetType="ItemsControl"> + <Setter Property="Opacity" Value="1"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding CreationMode}" Value="True"> + <Setter Property="Opacity" Value="0.3"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ItemsControl.Style> + <ItemsControl.ItemsPanel> <ItemsPanelTemplate> - <UniformGrid Margin="15 0 0 0" Columns="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=Items.Count}" IsItemsHost="True"></UniformGrid> + <Grid/> </ItemsPanelTemplate> - </Setter.Value> - </Setter> - <Setter Property="ItemContainerStyle"> - <Setter.Value> - <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> - <Setter Property="HorizontalContentAlignment" Value="Center"></Setter> - <Setter Property="VerticalContentAlignment" Value="Center"></Setter> - <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundBrush}"></Setter> - <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> - <Setter Property="Width" Value="200"></Setter> - <Setter Property="IsSelected" Value="{Binding IsSelected,Mode=OneWayToSource}"></Setter> - <Setter Property="Template"> - <Setter.Value> - <ControlTemplate TargetType="ListBoxItem"> - <Grid x:Name="grid" Margin="-15 0 0 0" Background="Transparent"> - <Viewbox Stretch="Fill"> - <Grid> - <Polygon Fill="{TemplateBinding Background}" Stretch="Fill" Points="0,30 15,0 85,0 100,30"></Polygon> - <Polygon Fill="White" Stretch="Fill" Points="0,30 15,0 85,0 100,30" IsHitTestVisible="False" Opacity="0.1"> - <Polygon.Style> - <Style TargetType="Polygon"> - <Setter Property="Visibility" Value="Hidden"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsMouseOver}" Value="True"> - <Setter Property="Visibility" Value="Visible"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </Polygon.Style> - </Polygon> - <Polyline Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" Stretch="Fill" Points="0,30 15,0 85,0 100,30" /> - <Rectangle VerticalAlignment="Bottom" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" /> - </Grid> - </Viewbox> - <ContentPresenter Content="{Binding Tab.Name}" TextElement.Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" /> - </Grid> - <ControlTemplate.Triggers> - <Trigger Property="IsSelected" Value="True"> - - </Trigger> - </ControlTemplate.Triggers> - </ControlTemplate> - </Setter.Value> - </Setter> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Visibility" Value="Hidden"></Setter> <Style.Triggers> - <Trigger Property="IsSelected" Value="True"> - <Setter Property="Background" Value="{StaticResource FSE_PrimaryAccentDarkBrush}"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> - <Setter Property="FontWeight" Value="SemiBold"></Setter> - <Setter Property="Panel.ZIndex" Value="200"></Setter> - </Trigger> - <Trigger Property="IsSelected" Value="False"> - <Setter Property="Panel.ZIndex" Value="-1"></Setter> - </Trigger> + <DataTrigger Binding="{Binding IsSelected}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> </Style.Triggers> </Style> - </Setter.Value> - </Setter> - </Style> - </ListBox.Style> - </ListBox> - <Rectangle Grid.Column="2" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> - </Grid> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <local:DiagnosticsTabView /> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> - <Grid x:Name="grid"> - <Viewbox Stretch="Fill" Margin="0 0 0 0" VerticalAlignment="Top" Width="{Binding ElementName=grid,Path=ActualWidth}" Height="{Binding ElementName=grid,Path=ActualHeight}"> - <ItemsControl x:Name="tabControl" Width="1810" Height="827" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> - <ItemsControl.ItemsPanel> - <ItemsPanelTemplate> - <Grid/> - </ItemsPanelTemplate> - </ItemsControl.ItemsPanel> - <ItemsControl.ItemContainerStyle> - <Style TargetType="FrameworkElement"> - <Setter Property="Visibility" Value="Hidden"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding IsSelected}" Value="True"> - <Setter Property="Visibility" Value="Visible"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </ItemsControl.ItemContainerStyle> - <ItemsControl.ItemTemplate> - <DataTemplate> - <local:DiagnosticsTabView /> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - </Viewbox> - </Grid> - </DockPanel> + <Grid Visibility="{Binding EditMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Grid Visibility="{Binding CreationMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <localControls:DiagnosticsSelectionGrid Opacity="0.4" RectanglesBackgroundBrush="{StaticResource FSE_PrimaryBackgroundLightBrush}" RectanglesHighlightBrush="{StaticResource FSE_BorderBrush}" Columns="{Binding SelectedTab.Tab.Columns}" Rows="{Binding SelectedTab.Tab.Rows}" SelectionCommand="{Binding SelectionCommand,Mode=OneWay}" RightClickCommand="{Binding AbortCreationCommand,Mode=OneWay}" Visibility="{Binding CreationMode,Converter={StaticResource BooleanToVisibilityConverter}}"/> + + <StackPanel Opacity="0.5" IsHitTestVisible="False" HorizontalAlignment="Center" VerticalAlignment="Center" > + <material:PackIcon Kind="Plus" HorizontalAlignment="Center" Width="32" Height="32" /> + <TextBlock FontSize="20" Margin="0 10 0 0">hold and drag the cursor over the desired widget cells</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 5 0 0" Foreground="{StaticResource FSE_GrayBrush}">(right click or escape to cancel the new widget)</TextBlock> + </StackPanel> + </Grid> + + <Grid Visibility="{Binding PasteMode,Converter={StaticResource BooleanToVisibilityConverter}}"> + <localControls:DiagnosticsSelectionGrid SelectionMode="Single" Opacity="0.4" RectanglesBackgroundBrush="{StaticResource FSE_PrimaryBackgroundLightBrush}" RectanglesHighlightBrush="{StaticResource FSE_BorderBrush}" Columns="{Binding SelectedTab.Tab.Columns}" Rows="{Binding SelectedTab.Tab.Rows}" SelectionCommand="{Binding SelectionCommand,Mode=OneWay}" RightClickCommand="{Binding AbortCreationCommand,Mode=OneWay}" Visibility="{Binding PasteMode,Converter={StaticResource BooleanToVisibilityConverter}}"/> + + <StackPanel Opacity="0.5" IsHitTestVisible="False" HorizontalAlignment="Center" VerticalAlignment="Center" > + <material:PackIcon Kind="Plus" HorizontalAlignment="Center" Width="32" Height="32" /> + <TextBlock FontSize="20" Margin="0 10 0 0">select the desired cell for pasting copied widgets</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 5 0 0" Foreground="{StaticResource FSE_GrayBrush}">(right click or escape to cancel pasting)</TextBlock> + </StackPanel> + </Grid> + + <localControls:DiagnosticsGridLinesEditor Visibility="{Binding ShowGridLines,Converter={StaticResource BooleanToVisibilityConverter}}" Columns="{Binding SelectedTab.Tab.Columns}" Rows="{Binding SelectedTab.Tab.Rows}"> + + </localControls:DiagnosticsGridLinesEditor> + </Grid> + </Grid> + </Viewbox> + </Grid> + </DockPanel> + + <controls:ToggleIconButton IsChecked="{Binding EditMode}" Width="24" Height="24" auth:AuthorizationHelper.Mode="Collapsed" auth:AuthorizationHelper.Permission="FSE_EditDiagnosticsProject" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0 10 0 0" Cursor="Hand" ToolTip="Edit Mode" UncheckedIcon="SettingsOutline" UncheckedForeground="{StaticResource FSE_GrayBrush}" CheckedForeground="{StaticResource FSE_OrangeBrush}" CheckedIcon="SettingsOutline" Foreground="{StaticResource FSE_OrangeBrush}"></controls:ToggleIconButton> - <controls:IconButton HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0 10 0 0" Cursor="Hand" ToolTip="Export diagnostics project" Icon="LightningBolt" Foreground="{StaticResource FSE_OrangeBrush}" Command="{Binding ExportProjectCommand}"></controls:IconButton> - </Grid> + <!--ZOOM? NOT SURE--> + <!--<DockPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0 -15 0 0"> + <material:PackIcon Kind="ZoomInOutline" DockPanel.Dock="Right" VerticalAlignment="Bottom" Margin="0 0 0 0"></material:PackIcon> + <Slider Style="{StaticResource MaterialDesignDiscreteSlider}" FocusVisualStyle="{x:Null}" Width="80" Minimum="0" Maximum="200" Value="100"></Slider> + </DockPanel>--> + </Grid> + </DockPanel> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json index 6baf6b4c2..a3df27042 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json @@ -83,53 +83,175 @@ { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "632ba431-4875-46f9-b9d6-39cbef3de2e5", "Column": 0, "Row": 0, "ColumnSpan": 3, - "RowSpan": 3 + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 }, { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "3e8ab666-ab5d-4f14-979c-bcad02007802", "Column": 3, "Row": 0, "ColumnSpan": 3, - "RowSpan": 3 + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 }, { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "1b6580fb-ef48-42f6-a340-775b5f586dad", "Column": 6, "Row": 0, "ColumnSpan": 3, - "RowSpan": 3 + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 }, { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "4f22da27-4b60-4ea1-871b-73b091cecdb9", "Column": 9, "Row": 0, "ColumnSpan": 3, - "RowSpan": 3 + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 }, { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel.RealTimeGraphMultiChannelWidget, Tango.FSE.Diagnostics", "Monitor": "DispensersMotorsFrequency", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "a72aa86c-ae39-42cc-8ca8-340abd4dd7f2", "Column": 0, "Row": 3, "ColumnSpan": 3, - "RowSpan": 3 + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 }, { "$type": "Tango.FSE.Diagnostics.Project.Widgets.Monitor.MonitorWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "DecimalPlaces": 0, + "Color": "#FFDCDCDC" + }, + "ID": "90899668-6cce-4f51-a401-3039fb2226b8", "Column": 0, "Row": 6, "ColumnSpan": 3, "RowSpan": 2, - "Width": 50 + "Width": 50.0, + "Height": 100.0 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.Input.InputWidget, Tango.FSE.Diagnostics", + "IO": "LS_DH_CLEAN_DOWN", + "EnableComponentSelection": true, + "ID": "3010722d-ef21-4c86-ad23-19956108169b", + "Column": 1, + "Row": 8, + "ColumnSpan": 1, + "RowSpan": 1, + "Width": 100.0, + "Height": 100.0 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.Motor.MotorWidget, Tango.FSE.Diagnostics", + "Motor": "MOTO_DH_CLEANHEAD", + "EnableComponentSelection": false, + "Settings": { + "Speed": 400, + "Color": "#FF79FF00" + }, + "ID": "625be286-0670-4784-b1ef-d78f854c4072", + "Column": 3, + "Row": 8, + "ColumnSpan": 4, + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.Dispenser.DispenserWidget, Tango.FSE.Diagnostics", + "Dispenser": "Dispenser2", + "EnableComponentSelection": false, + "Settings": { + "Speed": 400, + "Color": "#FF141414" + }, + "ID": "86e5683c-a9dc-46f4-a88b-087bff6f8432", + "Column": 8, + "Row": 8, + "ColumnSpan": 4, + "RowSpan": 3, + "Width": 100.0, + "Height": 100.0 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.Valve.ValveWidget, Tango.FSE.Diagnostics", + "Valve": "DispenserValve2", + "EnableComponentSelection": false, + "ID": "4829f0da-e128-42f9-a4af-621e895df3ef", + "Column": 3, + "Row": 3, + "ColumnSpan": 3, + "RowSpan": 2, + "Width": 100.0, + "Height": 100.0 } - ] }, { @@ -214,10 +336,22 @@ { "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", + "EnableComponentSelection": false, + "Settings": { + "Duration": "00:10:00", + "DecimalPlaces": 0, + "Min": 0.0, + "Max": 1000.0, + "AutoRange": true, + "Color": "#FF1E90FF" + }, + "ID": "e1da6427-d164-42f7-a4a8-44f804dd51df", "Column": 2, "Row": 2, "ColumnSpan": 6, - "RowSpan": 6 + "RowSpan": 6, + "Width": 100.0, + "Height": 100.0 } ] } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/packages.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/packages.config index dd8c723e4..fbddb4518 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/packages.config +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/packages.config @@ -7,4 +7,7 @@ <package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" /> <package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> + <package id="System.Reactive.Core" version="3.1.1" targetFramework="net461" /> + <package id="System.Reactive.Interfaces" version="3.1.1" targetFramework="net461" /> + <package id="System.Reactive.Linq" version="3.1.1" targetFramework="net461" /> </packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml index 29251ca31..bcac1bbaa 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml @@ -23,7 +23,7 @@ <KeyBinding Key="F5" Command="{Binding RunProjectCommand}" /> <KeyBinding Key="F6" Command="{Binding CompileProjectCommand}" /> <KeyBinding Modifiers="Ctrl" Key="S" Command="{Binding SaveProjectCommand}" /> - <KeyBinding Modifiers="Ctrl+Shift" Key="S" Command="{Binding SaveProjectCommand}" /> + <KeyBinding Modifiers="Ctrl+Shift" Key="S" Command="{Binding SaveAsProjectCommand}" /> <KeyBinding Modifiers="Ctrl" Key="N" Command="{Binding NewProjectCommand}" /> <KeyBinding Modifiers="Ctrl" Key="O" Command="{Binding OpenProjectCommand}" /> <KeyBinding Modifiers="Ctrl" Key="P" Command="{Binding TogglePublishPanelCommand}" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs index 266a5c090..4d3eb9885 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs @@ -32,12 +32,21 @@ namespace Tango.FSE.UsersAndRoles.Models set { _isSelected = value; RaisePropertyChangedAuto(); } } + private bool _isVisible; + public bool IsVisible + { + get { return _isVisible; } + set { _isVisible = value; RaisePropertyChangedAuto(); } + } + + public List<Roles> Dependencies { get; set; } public RoleModel(Role role, params Roles[] dependencies) { Role = role; IsEnabled = true; + IsVisible = true; Dependencies = new List<Roles>(); if (dependencies != null) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs index dec2651d1..e7fd962ec 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs @@ -191,7 +191,7 @@ namespace Tango.FSE.UsersAndRoles.ViewModels collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineAdministrator), Roles.FSETechnician, Roles.FSEAdministrator)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTestDesigner), Roles.FSETechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTestPublisher), Roles.FSETechnician, Roles.FSETwineTestDesigner)); - collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineDeveloper), Roles.FSETechnician)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineDeveloper), Roles.FSETechnician) { IsVisible = CurrentUser.HasRole(Roles.FSETwineDeveloper) }); } collection.ToList().ForEach(x => x.IsSelected = user.FSERoles.Any(y => y.Code == x.Role.Code)); diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml index a2ad81cf4..bbd99a965 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml @@ -113,7 +113,7 @@ <ListBox ScrollViewer.CanContentScroll="False" ScrollViewer.VerticalScrollBarVisibility="Disabled" Style="{StaticResource FSE_BlankListBox}" ItemsSource="{Binding RolesCollection}"> <ListBox.ItemTemplate> <DataTemplate> - <CheckBox Margin="0 10 0 0" IsChecked="{Binding IsSelected}" IsEnabled="{Binding IsEnabled}" Content="{Binding Role.Description}"></CheckBox> + <CheckBox Margin="0 10 0 0" IsChecked="{Binding IsSelected}" IsEnabled="{Binding IsEnabled}" Visibility="{Binding IsVisible,Converter={StaticResource BooleanToVisibilityConverter}}" Content="{Binding Role.Description}"></CheckBox> </DataTemplate> </ListBox.ItemTemplate> </ListBox> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs index 513982ba0..e14b61f22 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs @@ -44,7 +44,7 @@ namespace Tango.FSE.BL { using (ObservablesContext db = ObservablesContext.CreateDefault()) { - var entities = db.Set<TEntity>().WhereDynamic(expression.ToString()).ToList(); + var entities = db.Set<TEntity>().Where(expression).ToList(); using (var cache = DiskCache.CreateContext()) { diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs index e24c5b876..cc7f0f6da 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs @@ -19,6 +19,7 @@ namespace Tango.FSE.BL.Services public ReadOnlyEntityRepository<TechController, TechControllerDTO> Controllers { get; private set; } public ReadOnlyEntityRepository<TechHeater, TechHeaterDTO> Heaters { get; private set; } public ReadOnlyEntityRepository<TechValve, TechValveDTO> Valves { get; private set; } + public ReadOnlyEntityRepository<HardwareMotorType, HardwareMotorTypeDTO> Motors { get; private set; } public TechComponentsService() { @@ -26,43 +27,50 @@ namespace Tango.FSE.BL.Services x => x.ToObservable(), x => TechMonitorDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); IOs = new ReadOnlyEntityRepository<TechIo, TechIoDTO>( x => x.ToObservable(), x => TechIoDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); Dispensers = new ReadOnlyEntityRepository<TechDispenser, TechDispenserDTO>( x => x.ToObservable(), x => TechDispenserDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); Controllers = new ReadOnlyEntityRepository<TechController, TechControllerDTO>( x => x.ToObservable(), x => TechControllerDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); Heaters = new ReadOnlyEntityRepository<TechHeater, TechHeaterDTO>( x => x.ToObservable(), x => TechHeaterDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); Valves = new ReadOnlyEntityRepository<TechValve, TechValveDTO>( x => x.ToObservable(), x => TechValveDTO.FromObservable(x), DataResolverNode.InMemoryCache, - DataResolverNode.DiskCache, - DataResolverNode.Online); + DataResolverNode.Online, + DataResolverNode.DiskCache); + + Motors = new ReadOnlyEntityRepository<HardwareMotorType, HardwareMotorTypeDTO>( + x => x.ToObservable(), + x => HardwareMotorTypeDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.Online, + DataResolverNode.DiskCache); } public async Task Preload() @@ -73,6 +81,7 @@ namespace Tango.FSE.BL.Services await Controllers.FindAll(); await Heaters.FindAll(); await Valves.FindAll(); + await Motors.FindAll(); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Authorization/AuthorizationHelper.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Authorization/AuthorizationHelper.cs index 7ef470ad1..10e3dafd2 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Authorization/AuthorizationHelper.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Authorization/AuthorizationHelper.cs @@ -114,6 +114,8 @@ namespace Tango.FSE.Common.Authorization element.Unloaded += Element_Unloaded; } + if (_authenticationProvider == null) return; + var currentUser = _authenticationProvider.CurrentUser; var permission = GetPermission(element); var mode = GetMode(element); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.cs index f0485dd22..9a9c6de05 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.xaml index 679fefb78..21bf94f1c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconButton.xaml @@ -13,62 +13,101 @@ <DockPanel> <ContentPresenter Margin="5 0 0 0" DockPanel.Dock="Right" Content="{Binding}" VerticalAlignment="Center" /> <Grid Background="Transparent"> - <material:PackIcon IsHitTestVisible="False" RenderTransformOrigin="0.5, 0.5" Kind="{Binding RelativeSource={RelativeSource AncestorType=local:IconButton},Path=Icon}" Width="Auto" Height="Auto"> - <material:PackIcon.Style> - <Style TargetType="material:PackIcon"> - <Setter Property="RenderTransform"> - <Setter.Value> - <ScaleTransform ScaleX="1" ScaleY="1" /> - </Setter.Value> - </Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True"> - <Setter Property="RenderTransform"> - <Setter.Value> - <ScaleTransform ScaleX="1.2" ScaleY="1.2" /> - </Setter.Value> - </Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </material:PackIcon.Style> - </material:PackIcon> - <Canvas IsHitTestVisible="False"> - <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualHeight}"> - <Ellipse x:Name="ellipse" Fill="White" RenderTransformOrigin="0.5,0.5"> - <Ellipse.Style> - <Style TargetType="Ellipse"> - <Setter Property="Opacity" Value="0.2"></Setter> - <Setter Property="RenderTransform"> - <Setter.Value> - <ScaleTransform ScaleX="0" ScaleY="0" /> - </Setter.Value> - </Setter> - <Setter Property="Visibility" Value="Hidden"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True"> - <Setter Property="Visibility" Value="Visible"></Setter> - <DataTrigger.EnterActions> - <BeginStoryboard> - <Storyboard> - <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> - <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> - <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.2" To="0.001" Duration="00:00:0.5" DecelerationRatio="0.8" /> - </Storyboard> - </BeginStoryboard> - </DataTrigger.EnterActions> - </DataTrigger> - </Style.Triggers> - </Style> - </Ellipse.Style> - </Ellipse> - </Grid> - </Canvas> - </Grid> + <material:PackIcon IsHitTestVisible="False" RenderTransformOrigin="0.5, 0.5" Kind="{Binding RelativeSource={RelativeSource AncestorType=local:IconButton},Path=Icon}" Width="Auto" Height="Auto"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="1" ScaleY="1" /> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True"> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="1.2" ScaleY="1.2" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + <Canvas IsHitTestVisible="False"> + <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualHeight}"> + <Ellipse x:Name="ellipse" Fill="White" RenderTransformOrigin="0.5,0.5"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Opacity" Value="0.2"></Setter> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="0" ScaleY="0" /> + </Setter.Value> + </Setter> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + <DataTrigger.EnterActions> + <BeginStoryboard> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> + <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.2" To="0.001" Duration="00:00:0.5" DecelerationRatio="0.8" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + </Grid> + </Canvas> + </Grid> </DockPanel> </DataTemplate> </Setter.Value> </Setter> </Style> + <Style x:Key="FSE_IconButton_Flat_Pressed_Highlight" TargetType="{x:Type local:IconButton}" BasedOn="{StaticResource {x:Type local:IconButton}}"> + <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> + <Setter Property="Cursor" Value="Hand"></Setter> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="Padding" Value="0"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> + <Setter Property="material:RippleAssist.IsDisabled" Value="True"></Setter> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <DockPanel> + <ContentPresenter Margin="5 0 0 0" DockPanel.Dock="Right" Content="{Binding}" VerticalAlignment="Center" /> + <Grid Background="Transparent"> + <material:PackIcon IsHitTestVisible="False" RenderTransformOrigin="0.5, 0.5" Kind="{Binding RelativeSource={RelativeSource AncestorType=local:IconButton},Path=Icon}" Width="Auto" Height="Auto"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True"> + <Setter Property="Opacity" Value="0.6" /> + </DataTrigger> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsPressed}" Value="True"> + <Setter Property="Opacity" Value="1" /> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + </Grid> + </DockPanel> + </DataTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryAccentBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.cs new file mode 100644 index 000000000..bf3f69287 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.cs @@ -0,0 +1,35 @@ +using MaterialDesignThemes.Wpf; +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.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Common.Controls +{ + public class IconRepeatButton : RepeatButton + { + public PackIconKind Icon + { + get { return (PackIconKind)GetValue(IconProperty); } + set { SetValue(IconProperty, value); } + } + public static readonly DependencyProperty IconProperty = + DependencyProperty.Register("Icon", typeof(PackIconKind), typeof(IconRepeatButton), new PropertyMetadata(PackIconKind.BorderNone)); + + static IconRepeatButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(IconRepeatButton), new FrameworkPropertyMetadata(typeof(IconRepeatButton))); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.xaml new file mode 100644 index 000000000..db20acd64 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/IconRepeatButton.xaml @@ -0,0 +1,116 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.FSE.Common.Controls"> + + + <Style TargetType="{x:Type local:IconRepeatButton}" BasedOn="{StaticResource MaterialDesignToolForegroundButton}"> + <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> + <Setter Property="Cursor" Value="Hand"></Setter> + <Setter Property="material:RippleAssist.IsDisabled" Value="True"></Setter> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <DockPanel> + <ContentPresenter Margin="5 0 0 0" DockPanel.Dock="Right" Content="{Binding}" VerticalAlignment="Center" /> + <Grid Background="Transparent"> + <material:PackIcon IsHitTestVisible="False" RenderTransformOrigin="0.5, 0.5" Kind="{Binding RelativeSource={RelativeSource AncestorType=local:IconRepeatButton},Path=Icon}" Width="Auto" Height="Auto"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="1" ScaleY="1" /> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=RepeatButton},Path=IsMouseOver}" Value="True"> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="1.2" ScaleY="1.2" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + <Canvas IsHitTestVisible="False"> + <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas},Path=ActualHeight}"> + <Ellipse x:Name="ellipse" Fill="White" RenderTransformOrigin="0.5,0.5"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Opacity" Value="0.2"></Setter> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="0" ScaleY="0" /> + </Setter.Value> + </Setter> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=RepeatButton},Path=IsMouseOver}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + <DataTrigger.EnterActions> + <BeginStoryboard> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="0" To="4" Duration="00:00:0.5" DecelerationRatio="0.8" /> + <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.2" To="0.001" Duration="00:00:0.5" DecelerationRatio="0.8" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + </Grid> + </Canvas> + </Grid> + </DockPanel> + </DataTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="FSE_RepeatIconButton_Flat_Pressed_Highlight" TargetType="{x:Type local:IconRepeatButton}" BasedOn="{StaticResource {x:Type local:IconRepeatButton}}"> + <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> + <Setter Property="Cursor" Value="Hand"></Setter> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="Padding" Value="0"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> + <Setter Property="material:RippleAssist.IsDisabled" Value="True"></Setter> + <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter> + <Setter Property="VerticalContentAlignment" Value="Stretch"></Setter> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <DockPanel> + <ContentPresenter Visibility="{Binding Converter={StaticResource IsNullToVisibilityConverter}}" Margin="5 0 0 0" DockPanel.Dock="Right" Content="{Binding}" VerticalAlignment="Center" /> + <Grid Background="Transparent"> + <material:PackIcon VerticalAlignment="Stretch" IsHitTestVisible="False" RenderTransformOrigin="0.5, 0.5" Kind="{Binding RelativeSource={RelativeSource AncestorType=local:IconRepeatButton},Path=Icon}" Width="Auto" Height="Auto"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=RepeatButton},Path=IsMouseOver}" Value="True"> + <Setter Property="Opacity" Value="0.6" /> + </DataTrigger> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=RepeatButton},Path=IsPressed}" Value="True"> + <Setter Property="Opacity" Value="1" /> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + </Grid> + </DockPanel> + </DataTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryAccentBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index c4b27e530..5e4645c7f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -439,6 +439,27 @@ namespace Tango.FSE.Common } /// <summary> + /// Represents an FSE view model with a auto ModuleSettings property. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <seealso cref="Tango.FSE.Common.FSEViewModel" /> + public abstract class FSEViewModelWithModuleSettings<T> : FSEViewModel where T : SettingsBase + { + /// <summary> + /// Gets or sets the module settings. + /// </summary> + public T ModuleSettings { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="FSEViewModelWithModuleSettings{T}"/> class. + /// </summary> + public FSEViewModelWithModuleSettings() + { + ModuleSettings = SettingsManager.Default.GetOrCreate<T>(); + } + } + + /// <summary> /// Represents a FSE view model base class a View property as an instance of a <see cref="IFSEView"/> contract. /// </summary> /// <typeparam name="T"></typeparam> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/angelina.TTF b/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/angelina.TTF Binary files differnew file mode 100644 index 000000000..fe880ab91 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/angelina.TTF diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/indie.ttf b/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/indie.ttf Binary files differnew file mode 100644 index 000000000..1070aacda --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Fonts/indie.ttf diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_left.png b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_left.png Binary files differnew file mode 100644 index 000000000..3e7b2cb55 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_left.png diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_right.png b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_right.png Binary files differnew file mode 100644 index 000000000..bb217b671 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_right.png diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_top.png b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_top.png Binary files differnew file mode 100644 index 000000000..12f6ef010 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/shadow_top.png diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml index d25bcdaef..f956aa582 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml @@ -4,6 +4,7 @@ <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/IconButton.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/IconRepeatButton.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/TextIconButton.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSETabControl.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSEPanel.xaml" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml index ef3cb683e..91bf1816f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml @@ -13,4 +13,8 @@ <BitmapImage x:Key="FSE_Screw" UriSource="../Images/screw.png" /> <BitmapImage x:Key="FSE_Arrow_Right" UriSource="../Images/arrow_right.png" /> + <BitmapImage x:Key="FSE_Shadow_Top" UriSource="../Images/shadow_top.png" /> + <BitmapImage x:Key="FSE_Shadow_Left" UriSource="../Images/shadow_left.png" /> + <BitmapImage x:Key="FSE_Shadow_Right" UriSource="../Images/shadow_right.png" /> + </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/MahApps.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/MahApps.xaml new file mode 100644 index 000000000..deb614d8a --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/MahApps.xaml @@ -0,0 +1,973 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:mahShared="http://metro.mahapps.com/winfx/xaml/shared" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:commonControls="clr-namespace:Tango.FSE.Common.Controls" + xmlns:mdix="http://materialdesigninxaml.net/winfx/xaml/themes"> + + <ResourceDictionary.MergedDictionaries> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml" /> + </ResourceDictionary.MergedDictionaries> + + <ContextMenu x:Key="MaterialDesignDefaultContextMenu"> + <MenuItem Command="Cut"> + <MenuItem.Icon> + <mdix:PackIcon Kind="ContentCut" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Command="Copy"> + <MenuItem.Icon> + <mdix:PackIcon Kind="ContentCopy" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Command="Paste"> + <MenuItem.Icon> + <mdix:PackIcon Kind="ContentPaste" /> + </MenuItem.Icon> + </MenuItem> + <Separator /> + <MenuItem Command="SelectAll"> + <MenuItem.Icon> + <mdix:PackIcon Kind="SelectAll" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + + <Style x:Key="FSE_NumericUpDown_Flat" TargetType="{x:Type mah:NumericUpDown}" BasedOn="{StaticResource {x:Type mah:NumericUpDown}}"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundBrush}" /> + <Setter Property="BorderBrush" Value="{StaticResource FSE_GrayBrush}" /> + <Setter Property="BorderThickness" Value="0 0 0 0"/> + <Setter Property="mah:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.Focus}" /> + <Setter Property="mah:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.MouseOver}" /> + <Setter Property="mah:TextBoxHelper.ButtonFontSize" Value="{DynamicResource MahApps.Font.Size.Button.ClearText}" /> + <Setter Property="mah:TextBoxHelper.ButtonWidth" Value="22" /> + <Setter Property="mah:TextBoxHelper.IsMonitoring" Value="True" /> + <Setter Property="FocusVisualStyle" Value="{x:Null}" /> + <Setter Property="FontFamily" Value="{StaticResource flexo}" /> + <Setter Property="FontSize" Value="{StaticResource FSE_DefaultFontSize}" /> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}" /> + <Setter Property="HorizontalAlignment" Value="Stretch" /> + <Setter Property="HorizontalContentAlignment" Value="Stretch" /> + <Setter Property="MinHeight" Value="26" /> + <Setter Property="Height" Value="Auto"></Setter> + <Setter Property="MinWidth" Value="62" /> + <Setter Property="Padding" Value="0" /> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" /> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" /> + <Setter Property="SnapsToDevicePixels" Value="true" /> + <Setter Property="mdix:TextFieldAssist.UnderlineBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="mah:TextBoxHelper.UseFloatingWatermark" Value="{Binding Path=(mdix:HintAssist.IsFloating), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="mah:TextBoxHelper.Watermark" Value="{Binding Path=(mdix:HintAssist.Hint), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type mah:NumericUpDown}"> + <Border x:Name="Base" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(mdix:HintAssist.Hint), Mode=TwoWay, RelativeSource={RelativeSource AncestorType=mah:NumericUpDown}}"> + <Grid SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> + <Border /> + <Grid Margin="{TemplateBinding BorderThickness}"> + <Grid.ColumnDefinitions> + <ColumnDefinition x:Name="PART_LeftColumn" Width="*" /> + <ColumnDefinition x:Name="PART_MiddleColumn" Width="Auto" /> + <ColumnDefinition x:Name="PART_RightColumn" Width="Auto" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <TextBox x:Name="PART_TextBox" + Grid.Column="0" + Grid.Row="0" + MinWidth="20" + MinHeight="0" + Margin="0" + Padding="0" + HorizontalAlignment="{TemplateBinding HorizontalAlignment}" + HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalAlignment}" + VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" + mah:ControlsHelper.DisabledVisualElementVisibility="Collapsed" + mah:TextBoxHelper.ButtonContent="{TemplateBinding mah:TextBoxHelper.ButtonContent}" + mah:TextBoxHelper.ButtonContentTemplate="{TemplateBinding mah:TextBoxHelper.ButtonContentTemplate}" + mah:TextBoxHelper.ButtonFontFamily="{TemplateBinding mah:TextBoxHelper.ButtonFontFamily}" + mah:TextBoxHelper.ButtonFontSize="{TemplateBinding mah:TextBoxHelper.ButtonFontSize}" + mah:TextBoxHelper.ButtonWidth="{TemplateBinding mah:TextBoxHelper.ButtonWidth}" + mah:TextBoxHelper.ButtonsAlignment="{TemplateBinding ButtonsAlignment}" + mah:TextBoxHelper.ClearTextButton="{TemplateBinding mah:TextBoxHelper.ClearTextButton}" + mah:TextBoxHelper.HasText="{TemplateBinding mah:TextBoxHelper.HasText}" + mah:TextBoxHelper.SelectAllOnFocus="{TemplateBinding mah:TextBoxHelper.SelectAllOnFocus}" + mah:TextBoxHelper.UseFloatingWatermark="{TemplateBinding mah:TextBoxHelper.UseFloatingWatermark}" + mah:TextBoxHelper.Watermark="{TemplateBinding mah:TextBoxHelper.Watermark}" + mah:TextBoxHelper.WatermarkAlignment="{TemplateBinding mah:TextBoxHelper.WatermarkAlignment}" + mah:TextBoxHelper.WatermarkTrimming="{TemplateBinding mah:TextBoxHelper.WatermarkTrimming}" + mdix:TextFieldAssist.DecorationVisibility="Collapsed" + Background="{x:Null}" + ContextMenu="{StaticResource MaterialDesignDefaultContextMenu}" + FocusVisualStyle="{x:Null}" + TextAlignment="Left" + Focusable="{TemplateBinding Focusable}" + BorderThickness="0" + FontFamily="{TemplateBinding FontFamily}" + FontSize="{TemplateBinding FontSize}" + Foreground="{TemplateBinding Foreground}" + HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" + IsTabStop="{TemplateBinding IsTabStop}" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + TabIndex="{TemplateBinding TabIndex}" + VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" /> + + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericUp" + Grid.Column="1" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronUp"> + </commonControls:IconRepeatButton> + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericDown" + Grid.Column="2" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronDown"> + </commonControls:IconRepeatButton> + + <mdix:Underline + x:Name="Underline" + Grid.Column="0" + Grid.Row="1" + Grid.ColumnSpan="3" + Height="1" + Visibility="Collapsed" + CornerRadius="{Binding Path=(mdix:TextFieldAssist.UnderlineCornerRadius), RelativeSource={RelativeSource TemplatedParent}}" + Background="{Binding Path=(mdix:TextFieldAssist.UnderlineBrush), RelativeSource={RelativeSource TemplatedParent}}" /> + </Grid> + <Border x:Name="DisabledVisualElement" + Background="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderBrush="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding mah:ControlsHelper.CornerRadius}" + IsHitTestVisible="False" + Opacity="0" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(mah:ControlsHelper.DisabledVisualElementVisibility), Mode=OneWay}" /> + </Grid> + </Border> + <ControlTemplate.Triggers> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Right" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="2" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="0" /> + </MultiTrigger> + + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="DisabledVisualElement" Property="Opacity" Value="0.6" /> + </Trigger> + <Trigger Property="IsReadOnly" Value="True"> + + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsReadOnly" Value="False" /> + <Condition Property="InterceptManualEnter" Value="False" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_TextBox" Property="IsReadOnly" Value="True" /> + </MultiTrigger> + <Trigger Property="IsMouseOver" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_TextBox" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_NumericUp" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_NumericDown" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger Property="IsKeyboardFocusWithin" Value="True"> + <Setter TargetName="Underline" Property="IsActive" Value="True"/> + </Trigger> + <Trigger Property="HideUpDownButtons" Value="True"> + <Setter TargetName="PART_NumericDown" Property="Visibility" Value="Collapsed" /> + <Setter TargetName="PART_NumericUp" Property="Visibility" Value="Collapsed" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Setter Property="TextAlignment" Value="Right" /> + <Setter Property="UpDownButtonsWidth" Value="22" /> + <Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}" /> + </Style> + + <Style x:Key="FSE_NumericUpDown_Flat_Dark" TargetType="{x:Type mah:NumericUpDown}" BasedOn="{StaticResource {x:Type mah:NumericUpDown}}"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundDarkBrush}" /> + <Setter Property="BorderBrush" Value="{StaticResource FSE_GrayBrush}" /> + <Setter Property="BorderThickness" Value="0 0 0 0"/> + <Setter Property="mah:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.Focus}" /> + <Setter Property="mah:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.MouseOver}" /> + <Setter Property="mah:TextBoxHelper.ButtonFontSize" Value="{DynamicResource MahApps.Font.Size.Button.ClearText}" /> + <Setter Property="mah:TextBoxHelper.ButtonWidth" Value="22" /> + <Setter Property="mah:TextBoxHelper.IsMonitoring" Value="True" /> + <Setter Property="FocusVisualStyle" Value="{x:Null}" /> + <Setter Property="FontFamily" Value="{StaticResource flexo}" /> + <Setter Property="FontSize" Value="{StaticResource FSE_DefaultFontSize}" /> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}" /> + <Setter Property="HorizontalAlignment" Value="Stretch" /> + <Setter Property="HorizontalContentAlignment" Value="Stretch" /> + <Setter Property="MinHeight" Value="26" /> + <Setter Property="Height" Value="Auto"></Setter> + <Setter Property="MinWidth" Value="62" /> + <Setter Property="Padding" Value="0" /> + <Setter Property="mdix:ButtonAssist.CornerRadius" Value="5"></Setter> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" /> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" /> + <Setter Property="SnapsToDevicePixels" Value="true" /> + <Setter Property="mdix:TextFieldAssist.UnderlineBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="mah:TextBoxHelper.UseFloatingWatermark" Value="{Binding Path=(mdix:HintAssist.IsFloating), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="mah:TextBoxHelper.Watermark" Value="{Binding Path=(mdix:HintAssist.Hint), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type mah:NumericUpDown}"> + <Border x:Name="Base" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(mdix:ButtonAssist.CornerRadius), Mode=OneWay, RelativeSource={RelativeSource AncestorType=mah:NumericUpDown}}"> + <Grid SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> + <Border /> + <Grid Margin="{TemplateBinding BorderThickness}"> + <Grid.ColumnDefinitions> + <ColumnDefinition x:Name="PART_LeftColumn" Width="*" /> + <ColumnDefinition x:Name="PART_MiddleColumn" Width="Auto" /> + <ColumnDefinition x:Name="PART_RightColumn" Width="Auto" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <TextBox x:Name="PART_TextBox" + Grid.Column="0" + Grid.Row="0" + MinWidth="20" + MinHeight="0" + Margin="0" + Padding="0" + CaretBrush="{TemplateBinding Foreground}" + HorizontalAlignment="{TemplateBinding HorizontalAlignment}" + HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalAlignment}" + VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" + mah:ControlsHelper.DisabledVisualElementVisibility="Collapsed" + mah:TextBoxHelper.ButtonContent="{TemplateBinding mah:TextBoxHelper.ButtonContent}" + mah:TextBoxHelper.ButtonContentTemplate="{TemplateBinding mah:TextBoxHelper.ButtonContentTemplate}" + mah:TextBoxHelper.ButtonFontFamily="{TemplateBinding mah:TextBoxHelper.ButtonFontFamily}" + mah:TextBoxHelper.ButtonFontSize="{TemplateBinding mah:TextBoxHelper.ButtonFontSize}" + mah:TextBoxHelper.ButtonWidth="{TemplateBinding mah:TextBoxHelper.ButtonWidth}" + mah:TextBoxHelper.ButtonsAlignment="{TemplateBinding ButtonsAlignment}" + mah:TextBoxHelper.ClearTextButton="{TemplateBinding mah:TextBoxHelper.ClearTextButton}" + mah:TextBoxHelper.HasText="{TemplateBinding mah:TextBoxHelper.HasText}" + mah:TextBoxHelper.SelectAllOnFocus="{TemplateBinding mah:TextBoxHelper.SelectAllOnFocus}" + mah:TextBoxHelper.UseFloatingWatermark="{TemplateBinding mah:TextBoxHelper.UseFloatingWatermark}" + mah:TextBoxHelper.Watermark="{TemplateBinding mah:TextBoxHelper.Watermark}" + mah:TextBoxHelper.WatermarkAlignment="{TemplateBinding mah:TextBoxHelper.WatermarkAlignment}" + mah:TextBoxHelper.WatermarkTrimming="{TemplateBinding mah:TextBoxHelper.WatermarkTrimming}" + mdix:TextFieldAssist.DecorationVisibility="Collapsed" + Background="{x:Null}" + ContextMenu="{StaticResource MaterialDesignDefaultContextMenu}" + FocusVisualStyle="{x:Null}" + TextAlignment="Left" + Focusable="{TemplateBinding Focusable}" + BorderThickness="0" + FontFamily="{TemplateBinding FontFamily}" + FontSize="{TemplateBinding FontSize}" + Foreground="{TemplateBinding Foreground}" + HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" + IsTabStop="{TemplateBinding IsTabStop}" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + TabIndex="{TemplateBinding TabIndex}" + VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" /> + + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericUp" + Grid.Column="1" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronUp"> + </commonControls:IconRepeatButton> + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericDown" + Grid.Column="2" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronDown"> + </commonControls:IconRepeatButton> + + <mdix:Underline + x:Name="Underline" + Grid.Column="0" + Grid.Row="1" + Grid.ColumnSpan="3" + Height="1" + Visibility="Collapsed" + CornerRadius="{Binding Path=(mdix:TextFieldAssist.UnderlineCornerRadius), RelativeSource={RelativeSource TemplatedParent}}" + Background="{Binding Path=(mdix:TextFieldAssist.UnderlineBrush), RelativeSource={RelativeSource TemplatedParent}}" /> + </Grid> + <Border x:Name="DisabledVisualElement" + Background="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderBrush="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding mah:ControlsHelper.CornerRadius}" + IsHitTestVisible="False" + Opacity="0" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(mah:ControlsHelper.DisabledVisualElementVisibility), Mode=OneWay}" /> + </Grid> + </Border> + <ControlTemplate.Triggers> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Right" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="2" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="0" /> + </MultiTrigger> + + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="DisabledVisualElement" Property="Opacity" Value="0.6" /> + </Trigger> + <Trigger Property="IsReadOnly" Value="True"> + + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsReadOnly" Value="False" /> + <Condition Property="InterceptManualEnter" Value="False" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_TextBox" Property="IsReadOnly" Value="True" /> + </MultiTrigger> + <Trigger Property="IsMouseOver" Value="True"> + <!--<Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" />--> + </Trigger> + <Trigger SourceName="PART_TextBox" Property="IsFocused" Value="True"> + <!--<Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" />--> + </Trigger> + <Trigger SourceName="PART_NumericUp" Property="IsFocused" Value="True"> + <!--<Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" />--> + </Trigger> + <Trigger SourceName="PART_NumericDown" Property="IsFocused" Value="True"> + <!--<Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" />--> + </Trigger> + <Trigger Property="IsKeyboardFocusWithin" Value="True"> + <Setter TargetName="Underline" Property="IsActive" Value="True"/> + </Trigger> + <Trigger Property="HideUpDownButtons" Value="True"> + <Setter TargetName="PART_NumericDown" Property="Visibility" Value="Collapsed" /> + <Setter TargetName="PART_NumericUp" Property="Visibility" Value="Collapsed" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Setter Property="TextAlignment" Value="Right" /> + <Setter Property="UpDownButtonsWidth" Value="22" /> + <Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}" /> + </Style> + + + + <Style TargetType="{x:Type mah:NumericUpDown}"> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="BorderBrush" Value="{StaticResource FSE_GrayBrush}" /> + <Setter Property="BorderThickness" Value="0 0 0 1"/> + <Setter Property="mah:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.Focus}" /> + <Setter Property="mah:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.TextBox.Border.MouseOver}" /> + <Setter Property="mah:TextBoxHelper.ButtonFontSize" Value="{DynamicResource MahApps.Font.Size.Button.ClearText}" /> + <Setter Property="mah:TextBoxHelper.ButtonWidth" Value="22" /> + <Setter Property="mah:TextBoxHelper.IsMonitoring" Value="True" /> + <Setter Property="FocusVisualStyle" Value="{x:Null}" /> + <Setter Property="FontFamily" Value="{StaticResource flexo}" /> + <Setter Property="Height" Value="Auto"></Setter> + <Setter Property="FontSize" Value="{StaticResource FSE_DefaultFontSize}" /> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}" /> + <Setter Property="HorizontalAlignment" Value="Stretch" /> + <Setter Property="HorizontalContentAlignment" Value="Stretch" /> + <Setter Property="MinHeight" Value="26" /> + <Setter Property="MinWidth" Value="62" /> + <Setter Property="Padding" Value="0" /> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" /> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" /> + <Setter Property="SnapsToDevicePixels" Value="true" /> + <Setter Property="mdix:TextFieldAssist.UnderlineBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="mah:TextBoxHelper.UseFloatingWatermark" Value="{Binding Path=(mdix:HintAssist.IsFloating), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="mah:TextBoxHelper.Watermark" Value="{Binding Path=(mdix:HintAssist.Hint), Mode=TwoWay, RelativeSource={RelativeSource Self}}"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type mah:NumericUpDown}"> + <Grid SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> + <Border x:Name="Base" + Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding mah:ControlsHelper.CornerRadius}" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> + <Grid Margin="{TemplateBinding BorderThickness}"> + <Grid.ColumnDefinitions> + <ColumnDefinition x:Name="PART_LeftColumn" Width="*" /> + <ColumnDefinition x:Name="PART_MiddleColumn" Width="Auto" /> + <ColumnDefinition x:Name="PART_RightColumn" Width="Auto" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <TextBox x:Name="PART_TextBox" + Grid.Column="0" + Grid.Row="0" + MinWidth="20" + MinHeight="0" + Margin="0" + Padding="{TemplateBinding Padding}" + HorizontalAlignment="{TemplateBinding HorizontalAlignment}" + HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalAlignment}" + VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" + mah:ControlsHelper.DisabledVisualElementVisibility="Collapsed" + mah:TextBoxHelper.ButtonContent="{TemplateBinding mah:TextBoxHelper.ButtonContent}" + mah:TextBoxHelper.ButtonContentTemplate="{TemplateBinding mah:TextBoxHelper.ButtonContentTemplate}" + mah:TextBoxHelper.ButtonFontFamily="{TemplateBinding mah:TextBoxHelper.ButtonFontFamily}" + mah:TextBoxHelper.ButtonFontSize="{TemplateBinding mah:TextBoxHelper.ButtonFontSize}" + mah:TextBoxHelper.ButtonWidth="{TemplateBinding mah:TextBoxHelper.ButtonWidth}" + mah:TextBoxHelper.ButtonsAlignment="{TemplateBinding ButtonsAlignment}" + mah:TextBoxHelper.ClearTextButton="{TemplateBinding mah:TextBoxHelper.ClearTextButton}" + mah:TextBoxHelper.HasText="{TemplateBinding mah:TextBoxHelper.HasText}" + mah:TextBoxHelper.SelectAllOnFocus="{TemplateBinding mah:TextBoxHelper.SelectAllOnFocus}" + mah:TextBoxHelper.UseFloatingWatermark="{TemplateBinding mah:TextBoxHelper.UseFloatingWatermark}" + mah:TextBoxHelper.Watermark="{TemplateBinding mah:TextBoxHelper.Watermark}" + mah:TextBoxHelper.WatermarkAlignment="{TemplateBinding mah:TextBoxHelper.WatermarkAlignment}" + mah:TextBoxHelper.WatermarkTrimming="{TemplateBinding mah:TextBoxHelper.WatermarkTrimming}" + mdix:TextFieldAssist.DecorationVisibility="Collapsed" + Background="{x:Null}" + ContextMenu="{StaticResource MaterialDesignDefaultContextMenu}" + FocusVisualStyle="{x:Null}" + TextAlignment="Left" + Focusable="{TemplateBinding Focusable}" + BorderThickness="0" + FontFamily="{TemplateBinding FontFamily}" + FontSize="{TemplateBinding FontSize}" + Foreground="{TemplateBinding Foreground}" + HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" + IsTabStop="{TemplateBinding IsTabStop}" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + TabIndex="{TemplateBinding TabIndex}" + VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" /> + + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericUp" + Grid.Column="1" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronUp"> + </commonControls:IconRepeatButton> + <commonControls:IconRepeatButton Style="{StaticResource FSE_RepeatIconButton_Flat_Pressed_Highlight}" x:Name="PART_NumericDown" + Grid.Column="2" + Grid.Row="0" + Width="{TemplateBinding UpDownButtonsWidth}" + VerticalAlignment="Center" + Cursor="Hand" + Delay="{TemplateBinding Delay}" + IsTabStop="False" + Icon="ChevronDown"> + </commonControls:IconRepeatButton> + + <mdix:Underline + x:Name="Underline" + Grid.Column="0" + Grid.Row="1" + Grid.ColumnSpan="3" + Height="1" + Visibility="{Binding Path=(mdix:TextFieldAssist.DecorationVisibility), RelativeSource={RelativeSource TemplatedParent}}" + CornerRadius="{Binding Path=(mdix:TextFieldAssist.UnderlineCornerRadius), RelativeSource={RelativeSource TemplatedParent}}" + Background="{Binding Path=(mdix:TextFieldAssist.UnderlineBrush), RelativeSource={RelativeSource TemplatedParent}}" /> + </Grid> + <Border x:Name="DisabledVisualElement" + Background="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderBrush="{DynamicResource MahApps.Brushes.Control.Disabled}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding mah:ControlsHelper.CornerRadius}" + IsHitTestVisible="False" + Opacity="0" + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" + Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(mah:ControlsHelper.DisabledVisualElementVisibility), Mode=OneWay}" /> + </Grid> + <ControlTemplate.Triggers> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Left" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="0" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="2" /> + </MultiTrigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="ButtonsAlignment" Value="Right" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_LeftColumn" Property="Width" Value="*" /> + <Setter TargetName="PART_MiddleColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_NumericDown" Property="Grid.Column" Value="1" /> + <Setter TargetName="PART_NumericUp" Property="Grid.Column" Value="2" /> + <Setter TargetName="PART_RightColumn" Property="Width" Value="Auto" /> + <Setter TargetName="PART_TextBox" Property="Grid.Column" Value="0" /> + </MultiTrigger> + + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="DisabledVisualElement" Property="Opacity" Value="0.6" /> + </Trigger> + <Trigger Property="IsReadOnly" Value="True"> + + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsReadOnly" Value="False" /> + <Condition Property="InterceptManualEnter" Value="False" /> + </MultiTrigger.Conditions> + <Setter TargetName="PART_TextBox" Property="IsReadOnly" Value="True" /> + </MultiTrigger> + <Trigger Property="IsMouseOver" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_TextBox" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_NumericUp" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger SourceName="PART_NumericDown" Property="IsFocused" Value="True"> + <Setter TargetName="Base" Property="BorderBrush" Value="{StaticResource FSE_PrimaryAccentBrush}" /> + </Trigger> + <Trigger Property="IsKeyboardFocusWithin" Value="True"> + <Setter TargetName="Underline" Property="IsActive" Value="True"/> + </Trigger> + <Trigger Property="HideUpDownButtons" Value="True"> + <Setter TargetName="PART_NumericDown" Property="Visibility" Value="Collapsed" /> + <Setter TargetName="PART_NumericUp" Property="Visibility" Value="Collapsed" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Setter Property="TextAlignment" Value="Right" /> + <Setter Property="UpDownButtonsWidth" Value="22" /> + <Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}" /> + </Style> + + + + <!--RANGE SLIDER--> + <Style x:Key="MaterialDesign.RangeSlider.Thumb" + TargetType="Thumb"> + <Setter Property="Template" Value="{StaticResource MaterialDesignSliderThumb}" /> + </Style> + + <Style x:Key="MaterialDesign.RangeSlider.HorizontalMiddleThumb" + TargetType="{x:Type controls:MetroThumb}"> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="BorderThickness" Value="0" /> + <Setter Property="IsTabStop" Value="True" /> + <Setter Property="SnapsToDevicePixels" Value="True" /> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type controls:MetroThumb}"> + <Grid Background="{TemplateBinding Background}"> + <Rectangle Height="2" Fill="{TemplateBinding Foreground}" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="MaterialDesign.RangeSlider.VerticalMiddleThumb" + BasedOn="{StaticResource MaterialDesign.RangeSlider.HorizontalMiddleThumb}" + TargetType="{x:Type controls:MetroThumb}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type controls:MetroThumb}"> + <Grid Background="{TemplateBinding Background}"> + <Rectangle Width="2" Fill="{TemplateBinding Foreground}" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="MaterialDesign.RangeSlider.HorizontalTrack" + TargetType="{x:Type RepeatButton}"> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="Focusable" Value="False" /> + <Setter Property="IsTabStop" Value="False" /> + <Setter Property="OverridesDefaultStyle" Value="True" /> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type RepeatButton}"> + <Grid Background="{TemplateBinding Background}"> + <Rectangle Height="2" Fill="{TemplateBinding Foreground}" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="MaterialDesign.RangeSlider.VerticalTrack" + BasedOn="{StaticResource MaterialDesign.RangeSlider.HorizontalTrack}" + TargetType="{x:Type RepeatButton}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type RepeatButton}"> + <Grid Background="{TemplateBinding Background}"> + <Rectangle Width="2" Fill="{TemplateBinding Foreground}" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <ControlTemplate x:Key="MaterialDesignMahAppsRangeSliderHorizontal" + TargetType="controls:RangeSlider"> + <Grid x:Name="PART_Container" + VerticalAlignment="{TemplateBinding VerticalContentAlignment}" + Background="{TemplateBinding Background}"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" MinHeight="{TemplateBinding controls:RangeSlider.MinHeight}" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <TickBar x:Name="PART_TopTick" + Grid.Row="0" + Height="4" + Fill="{TemplateBinding Foreground}" + IsSelectionRangeEnabled="{TemplateBinding IsSelectionRangeEnabled}" + Maximum="{TemplateBinding Maximum}" + Minimum="{TemplateBinding Minimum}" + Placement="Top" + ReservedSpace="{DynamicResource MahApps.Sizes.Slider.HorizontalThumb.Width}" + SelectionEnd="{TemplateBinding SelectionEnd}" + SelectionStart="{TemplateBinding SelectionStart}" + TickFrequency="{TemplateBinding TickFrequency}" + Ticks="{TemplateBinding Ticks}" + Visibility="Collapsed" /> + <TickBar x:Name="PART_BottomTick" + Grid.Row="2" + Height="4" + Fill="{TemplateBinding Foreground}" + IsSelectionRangeEnabled="{TemplateBinding IsSelectionRangeEnabled}" + Maximum="{TemplateBinding Maximum}" + Minimum="{TemplateBinding Minimum}" + Placement="Bottom" + ReservedSpace="{DynamicResource MahApps.Sizes.Slider.HorizontalThumb.Width}" + SelectionEnd="{TemplateBinding SelectionEnd}" + SelectionStart="{TemplateBinding SelectionStart}" + TickFrequency="{TemplateBinding TickFrequency}" + Ticks="{TemplateBinding Ticks}" + Visibility="Collapsed" /> + <StackPanel x:Name="PART_RangeSliderContainer" + Grid.Row="1" + Background="Transparent" + Orientation="Horizontal"> + <RepeatButton x:Name="PART_LeftEdge" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillBrush)}" + Style="{DynamicResource MaterialDesign.RangeSlider.HorizontalTrack}" /> + + <controls:MetroThumb x:Name="PART_LeftThumb" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillBrush)}" + Cursor="Arrow" + Style="{DynamicResource MaterialDesign.RangeSlider.Thumb}" /> + <controls:MetroThumb x:Name="PART_MiddleThumb" + MinWidth="{TemplateBinding MinRangeWidth}" + Cursor="Hand" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillBrush)}" + Style="{DynamicResource MaterialDesign.RangeSlider.HorizontalMiddleThumb}" /> + <controls:MetroThumb x:Name="PART_RightThumb" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillBrush)}" + Cursor="Arrow" + Style="{DynamicResource MaterialDesign.RangeSlider.Thumb}" /> + + <RepeatButton x:Name="PART_RightEdge" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillBrush)}" + Style="{DynamicResource MaterialDesign.RangeSlider.HorizontalTrack}" /> + </StackPanel> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="TickPlacement" Value="TopLeft"> + <Setter TargetName="PART_TopTick" Property="Visibility" Value="Visible" /> + </Trigger> + <Trigger Property="TickPlacement" Value="BottomRight"> + <Setter TargetName="PART_BottomTick" Property="Visibility" Value="Visible" /> + </Trigger> + <Trigger Property="TickPlacement" Value="Both"> + <Setter TargetName="PART_BottomTick" Property="Visibility" Value="Visible" /> + <Setter TargetName="PART_TopTick" Property="Visibility" Value="Visible" /> + </Trigger> + + <Trigger Property="IsMouseOver" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillHoverBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillHoverBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillHoverBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillHoverBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillHoverBrush)}" /> + </Trigger> + <Trigger SourceName="PART_LeftEdge" Property="IsPressed" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger SourceName="PART_RightEdge" Property="IsPressed" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger SourceName="PART_MiddleThumb" Property="IsDragging" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillDisabledBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillDisabledBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillDisabledBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillDisabledBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillDisabledBrush)}" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + + <ControlTemplate x:Key="MaterialDesignRangeSliderVertical" + TargetType="controls:RangeSlider"> + <Grid x:Name="PART_Container" + HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" + Background="{TemplateBinding Background}"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" MinWidth="{TemplateBinding controls:RangeSlider.MinWidth}" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <TickBar x:Name="PART_TopTick" + Grid.Column="0" + Width="4" + Fill="{TemplateBinding Foreground}" + IsSelectionRangeEnabled="{TemplateBinding IsSelectionRangeEnabled}" + Maximum="{TemplateBinding Maximum}" + Minimum="{TemplateBinding Minimum}" + Placement="Left" + ReservedSpace="{DynamicResource MahApps.Sizes.Slider.VerticalThumb.Height}" + SelectionEnd="{TemplateBinding SelectionEnd}" + SelectionStart="{TemplateBinding SelectionStart}" + TickFrequency="{TemplateBinding TickFrequency}" + Ticks="{TemplateBinding Ticks}" + Visibility="Collapsed" /> + <TickBar x:Name="PART_BottomTick" + Grid.Column="2" + Width="4" + Fill="{TemplateBinding Foreground}" + IsSelectionRangeEnabled="{TemplateBinding IsSelectionRangeEnabled}" + Maximum="{TemplateBinding Maximum}" + Minimum="{TemplateBinding Minimum}" + Placement="Right" + ReservedSpace="{DynamicResource MahApps.Sizes.Slider.VerticalThumb.Height}" + SelectionEnd="{TemplateBinding SelectionEnd}" + SelectionStart="{TemplateBinding SelectionStart}" + TickFrequency="{TemplateBinding TickFrequency}" + Ticks="{TemplateBinding Ticks}" + Visibility="Collapsed" /> + <StackPanel x:Name="PART_RangeSliderContainer" + Grid.Column="1" + Background="Transparent" + Orientation="Vertical"> + <RepeatButton x:Name="PART_RightEdge" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillBrush)}" + Style="{DynamicResource MaterialDesign.RangeSlider.VerticalTrack}" /> + + <controls:MetroThumb x:Name="PART_RightThumb" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillBrush)}" + Cursor="Arrow" + Style="{DynamicResource MaterialDesign.RangeSlider.Thumb}" /> + <controls:MetroThumb x:Name="PART_MiddleThumb" + MinHeight="{TemplateBinding MinRangeWidth}" + Cursor="Hand" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillBrush)}" + Style="{StaticResource MaterialDesign.RangeSlider.VerticalMiddleThumb}" /> + <controls:MetroThumb x:Name="PART_LeftThumb" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillBrush)}" + Cursor="Arrow" + Style="{DynamicResource MaterialDesign.RangeSlider.Thumb}" /> + + <RepeatButton x:Name="PART_LeftEdge" + Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillBrush)}" + Style="{DynamicResource MaterialDesign.RangeSlider.VerticalTrack}" /> + </StackPanel> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="TickPlacement" Value="TopLeft"> + <Setter TargetName="PART_TopTick" Property="Visibility" Value="Visible" /> + </Trigger> + <Trigger Property="TickPlacement" Value="BottomRight"> + <Setter TargetName="PART_BottomTick" Property="Visibility" Value="Visible" /> + </Trigger> + <Trigger Property="TickPlacement" Value="Both"> + <Setter TargetName="PART_BottomTick" Property="Visibility" Value="Visible" /> + <Setter TargetName="PART_TopTick" Property="Visibility" Value="Visible" /> + </Trigger> + + <Trigger Property="IsMouseOver" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillHoverBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillHoverBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillHoverBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillHoverBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillHoverBrush)}" /> + </Trigger> + <Trigger SourceName="PART_LeftEdge" Property="IsPressed" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger SourceName="PART_RightEdge" Property="IsPressed" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger SourceName="PART_MiddleThumb" Property="IsDragging" Value="True"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillPressedBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillPressedBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillPressedBrush)}" /> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="PART_LeftEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillDisabledBrush)}" /> + <Setter TargetName="PART_LeftThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillDisabledBrush)}" /> + <Setter TargetName="PART_MiddleThumb" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackValueFillDisabledBrush)}" /> + <Setter TargetName="PART_RightEdge" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.TrackFillDisabledBrush)}" /> + <Setter TargetName="PART_RightThumb" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:SliderHelper.ThumbFillDisabledBrush)}" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + + <Style TargetType="{x:Type controls:RangeSlider}"> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="Margin" Value="6 0" /> + <Setter Property="controls:SliderHelper.ThumbFillBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.ThumbFillDisabledBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.ThumbFillHoverBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.ThumbFillPressedBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.TrackFillBrush" Value="{DynamicResource MaterialDesignCheckBoxOff}" /> + <Setter Property="controls:SliderHelper.TrackFillDisabledBrush" Value="{DynamicResource MaterialDesignCheckBoxDisabled}" /> + <Setter Property="controls:SliderHelper.TrackFillHoverBrush" Value="{DynamicResource MaterialDesignCheckBoxOff}" /> + <Setter Property="controls:SliderHelper.TrackFillPressedBrush" Value="{DynamicResource MaterialDesignCheckBoxOff}" /> + <Setter Property="controls:SliderHelper.TrackValueFillBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.TrackValueFillDisabledBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.TrackValueFillHoverBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="controls:SliderHelper.TrackValueFillPressedBrush" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" /> + <Setter Property="HorizontalContentAlignment" Value="Stretch" /> + <Setter Property="Template" Value="{StaticResource MaterialDesignMahAppsRangeSliderHorizontal}" /> + <Setter Property="VerticalContentAlignment" Value="Stretch" /> + <Style.Triggers> + <Trigger Property="Orientation" Value="Vertical"> + <Setter Property="Template" Value="{StaticResource MaterialDesignRangeSliderVertical}" /> + </Trigger> + </Style.Triggers> + </Style> + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml index e4b3c00a2..b78f3d029 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml @@ -4,6 +4,7 @@ xmlns:actions="clr-namespace:Tango.FSE.Common.EventTriggerActions" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:wpf="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:Tango.FSE.Common.Resources"> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index f4cd07490..8532c3e3a 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -74,6 +74,7 @@ <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> + <Reference Include="PresentationFramework.Aero" /> <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> @@ -116,6 +117,7 @@ <Compile Include="Connectivity\IConnectivityProvider.cs" /> <Compile Include="Console\IConsoleProvider.cs" /> <Compile Include="Controls\FSEGroupBox.cs" /> + <Compile Include="Controls\IconRepeatButton.cs" /> <Compile Include="Controls\KeepAliveTabControl.cs" /> <Compile Include="Controls\ConnectedMachineIcon.xaml.cs"> <DependentUpon>ConnectedMachineIcon.xaml</DependentUpon> @@ -247,6 +249,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Controls\IconRepeatButton.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Controls\IconButton.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -315,6 +321,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Resources\MahApps.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Resources\Styles.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -373,6 +383,8 @@ <Resource Include="Fonts\Flexo-ThinIt.otf" /> <Resource Include="Fonts\Caveat-Bold.ttf" /> <Resource Include="Fonts\Caveat-Regular.ttf" /> + <Resource Include="Fonts\indie.ttf" /> + <Resource Include="Fonts\angelina.TTF" /> <None Include="packages.config" /> <None Include="Properties\Settings.settings"> <Generator>SettingsSingleFileGenerator</Generator> @@ -506,6 +518,11 @@ <ItemGroup> <Resource Include="Images\transparent_small.jpg" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\shadow_left.png" /> + <Resource Include="Images\shadow_right.png" /> + <Resource Include="Images\shadow_top.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <PropertyGroup> <PreBuildEvent> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml index 8f0cb79fd..73680103b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml @@ -18,6 +18,8 @@ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />--> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> + <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.Slider.xaml" /> + <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Themes/RangeSlider.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" /> @@ -53,6 +55,9 @@ </ResourceDictionary> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.ProgressBar.xaml"/> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ComboBox.xaml" /> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Menu.xaml" /> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Slider.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml"/> @@ -63,6 +68,7 @@ <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Styles.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Graphs.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/MahApps.xaml" /> <ResourceDictionary> <!--OVERRIDE MAHAPPS--> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/FSEApplication/DefaultFSEApplicationManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/FSEApplication/DefaultFSEApplicationManager.cs index c20116432..e0465d307 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/FSEApplication/DefaultFSEApplicationManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/FSEApplication/DefaultFSEApplicationManager.cs @@ -382,6 +382,12 @@ namespace Tango.FSE.UI.FSEApplication } catch { } + try + { + SettingsManager.Default.Save(); + } + catch { } + LogManager.Log("Disposing disk cache..."); DiskCacheManager.Default.Dispose(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml index aa6413cab..bb18a26e0 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml @@ -21,7 +21,7 @@ UseNoneWindowStyle="True" EnableDWMDropShadow="True" MinWidth="1280" - MinHeight="720" + MinHeight="690" BorderThickness="1" BorderBrush="Gray" FontFamily="{StaticResource flexo}" diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/InternalModuleViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/InternalModuleViewVM.cs index 81927608f..970d77b89 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/InternalModuleViewVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/InternalModuleViewVM.cs @@ -16,16 +16,16 @@ namespace Tango.FSE.UI.ViewModels { if (AuthenticationProvider.CurrentUser.HasPermission(Tango.BL.Enumerations.Permissions.FSE_RunFSE)) { - NavigationManager.MenuItems.Add(new NavigationMenuItem(() => - { - NavigationManager.NavigateTo<InternalModule>(nameof(AccountView)); - }) - { - Name = "Account", - Index = -1, - Description = "Manage your account details", - Image = ResourceHelper.GetImageFromResources("Images/Menu/account.png"), - }); + //NavigationManager.MenuItems.Add(new NavigationMenuItem(() => + //{ + // NavigationManager.NavigateTo<InternalModule>(nameof(AccountView)); + //}) + //{ + // Name = "Account", + // Index = -1, + // Description = "Manage your account details", + // Image = ResourceHelper.GetImageFromResources("Images/Menu/account.png"), + //}); NavigationManager.MenuItems.Add(new NavigationMenuItem(() => { @@ -38,16 +38,16 @@ namespace Tango.FSE.UI.ViewModels Image = ResourceHelper.GetImageFromResources("Images/Menu/events.png"), }); - NavigationManager.MenuItems.Add(new NavigationMenuItem(() => - { - NavigationManager.NavigateTo<InternalModule>(nameof(SettingsView)); - }) - { - Name = "Settings", - Index = 100, - Description = "Configuration of your Tango FSE", - Image = ResourceHelper.GetImageFromResources("Images/Menu/settings.png"), - }); + //NavigationManager.MenuItems.Add(new NavigationMenuItem(() => + //{ + // NavigationManager.NavigateTo<InternalModule>(nameof(SettingsView)); + //}) + //{ + // Name = "Settings", + // Index = 100, + // Description = "Configuration of your Tango FSE", + // Image = ResourceHelper.GetImageFromResources("Images/Menu/settings.png"), + //}); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml index 5f5adfe59..612cbfa8b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml @@ -24,7 +24,6 @@ </Grid.RowDefinitions> <Grid Grid.Row="1"> - <Grid x:Name="layoutGrid"> <Grid.RowDefinitions> <RowDefinition Height="1*" /> @@ -34,7 +33,7 @@ </Grid.RowDefinitions> <ScrollViewer Focusable="False" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> - <controls:NavigationControl Focusable="False" x:Name="NavigationControl" VerticalAlignment="Top" TransitionAlwaysFades="True" Height="{Binding ElementName=layoutGrid,Path=ActualHeight,Converter={StaticResource MathOperatorConverter},ConverterParameter='-33'}"> + <controls:NavigationControl Focusable="False" UseDefferedRendering="True" x:Name="NavigationControl" VerticalAlignment="Top" TransitionAlwaysFades="True" Height="{Binding ElementName=layoutGrid,Path=ActualHeight,Converter={StaticResource MathOperatorConverter},ConverterParameter='-33'}"> <!--MODULES--> </controls:NavigationControl> </ScrollViewer> @@ -127,6 +126,8 @@ </Grid> </Grid> + <Image IsHitTestVisible="False" Source="{StaticResource FSE_Shadow_Top}" VerticalAlignment="Top" Stretch="Fill" Height="10" Opacity="0.6" /> + <Grid x:Name="paneMask" Background="{StaticResource FSE_SemiTransparentBrush}" Visibility="{Binding IsConnectionPaneOpened,Converter={StaticResource BooleanToVisibilityConverter},FallbackValue=Collapsed}"> <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewMouseUp"> @@ -190,9 +191,6 @@ <!--Top Bar--> <Grid Background="{StaticResource FSE_PrimaryBackgroundLightBrush}"> - <Grid.Effect> - <DropShadowEffect BlurRadius="10" /> - </Grid.Effect> <Polygon HorizontalAlignment="Right" Points="220,0 300,0 300,100 0,100" Width="350" Stretch="Fill"> <Polygon.Fill> @@ -234,14 +232,14 @@ <TextBlock FontSize="12" Foreground="{StaticResource FSE_GrayBrush}" TextTrimming="CharacterEllipsis" MaxWidth="170" FontStyle="Italic" Margin="10 5 0 0" VerticalAlignment="Center"> <Run Text="{Binding AuthenticationProvider.CurrentUser.Organization.Name}"></Run> , - <Run Text="{Binding AuthenticationProvider.CurrentUser.FSERoles[0].Name}"> + <Run Text="{Binding AuthenticationProvider.CurrentUser.FSERoles[0].Description}"> <Run.ToolTip> <ItemsControl ItemsSource="{Binding AuthenticationProvider.CurrentUser.FSERoles}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="2"> <material:PackIcon Kind="AccountKey" Width="16" Height="16" /> - <TextBlock Margin="5 0 0 0" Text="{Binding Name}"></TextBlock> + <TextBlock Margin="5 0 0 0" Text="{Binding Description}"></TextBlock> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LoginView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LoginView.xaml index f818d0c10..a20ae68b3 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LoginView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LoginView.xaml @@ -9,6 +9,7 @@ xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:local="clr-namespace:Tango.FSE.UI.Views" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:LoginViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.LoginViewVM}"> @@ -44,7 +45,7 @@ <Grid ClipToBounds="True"> <Image Source="/Images/Abstracts/abstract1.png" Stretch="UniformToFill" Opacity="0.8" HorizontalAlignment="Right" Width="{Binding RelativeSource={RelativeSource AncestorType=Grid},Path=ActualWidth,Converter={StaticResource MathOperatorConverter},ConverterParameter='*1.5'}"/> <StackPanel> - <TextBlock HorizontalAlignment="Center" Margin="0 30 0 0" FontSize="40" TextAlignment="Center" TextWrapping="Wrap" Foreground="{StaticResource FSE_PrimaryForegroundBrush}">Welcome</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 70 0 0" FontSize="40" TextAlignment="Center" FontWeight="Bold" TextWrapping="Wrap" Foreground="{StaticResource FSE_PrimaryForegroundBrush}">TANGO FSE</TextBlock> </StackPanel> <Image Source="{StaticResource FSE_Machine_Full}" VerticalAlignment="Bottom" RenderOptions.BitmapScalingMode="Fant" Margin="0 0 0 150" MaxWidth="300" MinWidth="100" /> <Rectangle HorizontalAlignment="Right" StrokeThickness="1" Stroke="{StaticResource FSE_BorderBrush}" StrokeDashArray="5" /> @@ -78,7 +79,7 @@ <StackPanel controls:NavigationControl.NavigationName="Logging"> <ProgressBar Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center" IsIndeterminate="{Binding IsBusy}" Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" /> - <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">Logging you in, please wait...</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">logging you in, please wait...</TextBlock> <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" Text="{Binding Status}" Foreground="{StaticResource FSE_GrayBrush}"></TextBlock> </StackPanel> @@ -104,7 +105,7 @@ <StackPanel controls:NavigationControl.NavigationName="ChangingPassword"> <ProgressBar Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center" IsIndeterminate="{Binding IsBusy}" Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" /> - <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">Updating your password, please wait...</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">updating your password, please wait...</TextBlock> </StackPanel> <StackPanel TextElement.FontSize="16" controls:NavigationControl.NavigationName="ForgotPassword"> @@ -128,7 +129,7 @@ <StackPanel controls:NavigationControl.NavigationName="SendingForgotPasswordEmail"> <ProgressBar Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center" IsIndeterminate="{Binding IsBusy}" Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" /> - <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">Sending password reset email, please wait...</TextBlock> + <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="18">sending password reset email, please wait...</TextBlock> </StackPanel> </controls:NavigationControl> </Grid> diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs index 2dfea3ff3..ae77c26d0 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -659,10 +659,11 @@ namespace Tango.PPC.Common.MachineUpdate { throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); } - if (!op.CanPrint) - { - throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); - } + } + + if (!op.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); } //Connect to machine service and get matching packages for this machine. @@ -970,6 +971,11 @@ namespace Tango.PPC.Common.MachineUpdate { LogManager.Log("Starting database update..."); + if (!_machineProvider.MachineOperator.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {_machineProvider.MachineOperator} status.")); + } + UpdateProgress("Updating Database", "Initializing..."); LogManager.Log("Looking for update scripts configuration on application path..."); @@ -1241,10 +1247,11 @@ namespace Tango.PPC.Common.MachineUpdate { throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); } - if (!op.CanPrint) - { - throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); - } + } + + if (!op.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); } UpdateProgress("Exploring package", "Extracting..."); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs index a7ae770f3..23fecdf0e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs @@ -8,4 +8,4 @@ using System.Windows; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Tango PPC Application")] -[assembly: AssemblyVersion("1.1.15.0")] +[assembly: AssemblyVersion("1.1.16.0")] diff --git a/Software/Visual_Studio/Tango.BL/Entities/Job.cs b/Software/Visual_Studio/Tango.BL/Entities/Job.cs index cf987f306..5cd756f27 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/Job.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/Job.cs @@ -389,34 +389,42 @@ namespace Tango.BL.Entities public BitmapSource CreateSegmentsPie(double width, double height) { - Bitmap bmp = new Bitmap((int)width, (int)height); - - using (Graphics g = Graphics.FromImage(bmp)) + try { - g.Clear(Color.Transparent); - g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; - g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High; - g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; - - int fromAngle = -90; - double totalLength = Segments.Sum(x => x.Length); //Excluding inter segment. + Bitmap bmp = new Bitmap((int)width, (int)height); - foreach (var segment in OrderedSegments) + using (Graphics g = Graphics.FromImage(bmp)) { - int toAngle = (int)((segment.Length / totalLength) * 360d); - Rectangle rect = new Rectangle(0, 0, bmp.Width - 2, bmp.Height - 2); - g.FillPie(segment.CreateGdiBrush(bmp.Width - 2, bmp.Height - 2), rect, fromAngle, toAngle); + g.Clear(Color.Transparent); + g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; + g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High; + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + + int fromAngle = -90; + double totalLength = Segments.Sum(x => x.Length); //Excluding inter segment. + + foreach (var segment in OrderedSegments) + { + int toAngle = (int)((segment.Length / totalLength) * 360d); + Rectangle rect = new Rectangle(0, 0, bmp.Width - 2, bmp.Height - 2); + g.FillPie(segment.CreateGdiBrush(bmp.Width - 2, bmp.Height - 2), rect, fromAngle, toAngle); - Pen pen = new Pen(Color.Gainsboro); - g.DrawEllipse(pen, rect); - pen.Dispose(); - fromAngle += toAngle; + Pen pen = new Pen(Color.Gainsboro); + g.DrawEllipse(pen, rect); + pen.Dispose(); + fromAngle += toAngle; + } } - } - var source = bmp.ToBitmapSource(); - bmp.Dispose(); - return source; + var source = bmp.ToBitmapSource(); + bmp.Dispose(); + return source; + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error occurred while trying to create job pie image for job '{Name}'."); + return null; + } } /// <summary> diff --git a/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs b/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs index 514ce925d..38a760af4 100644 --- a/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs +++ b/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs @@ -235,5 +235,11 @@ namespace Tango.BL.Enumerations [Description("Allows executing command prompt commands remotely")] FSE_ExecuteRemoteConsoleCommands = 1014, + /// <summary> + /// (Allows editing of the default diagnostics project) + /// </summary> + [Description("Allows editing of the default diagnostics project")] + FSE_EditDiagnosticsProject = 1015, + } } diff --git a/Software/Visual_Studio/Tango.Core/ExtendedObject.cs b/Software/Visual_Studio/Tango.Core/ExtendedObject.cs index 63a75480c..f09a82ae9 100644 --- a/Software/Visual_Studio/Tango.Core/ExtendedObject.cs +++ b/Software/Visual_Studio/Tango.Core/ExtendedObject.cs @@ -82,7 +82,7 @@ namespace Tango.Core { InvokeUI(() => { - foreach (var prop in this.GetType().GetProperties().Where(x => x.PropertyType == typeof(RelayCommand))) + foreach (var prop in this.GetType().GetProperties().Where(x => typeof(RelayCommand).IsAssignableFrom(x.PropertyType))) { var value = prop.GetValue(this) as RelayCommand; diff --git a/Software/Visual_Studio/Tango.Core/TangoProgress.cs b/Software/Visual_Studio/Tango.Core/TangoProgress.cs index ccec0e546..e8a82a3b0 100644 --- a/Software/Visual_Studio/Tango.Core/TangoProgress.cs +++ b/Software/Visual_Studio/Tango.Core/TangoProgress.cs @@ -73,7 +73,10 @@ namespace Tango.Core /// </summary> public TangoProgress(String message, bool isIndeterminate = true, T value = default(T), T maximum = default(T)) : this() { - + Message = message; + IsIndeterminate = isIndeterminate; + Value = value; + Maximum = maximum; } public override string ToString() diff --git a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs index 79e6739af..bc17ec394 100644 --- a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs +++ b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs @@ -549,66 +549,74 @@ namespace Tango.Touch.Controls for (int i = 0; i < ordered.Count; i++) { - ContentPresenter contentPresenter = ordered[i]; - LightTouchDataGridRow row = contentPresenter.FindChild<LightTouchDataGridRow>(); + try + { + ContentPresenter contentPresenter = ordered[i]; - bool display = true; + LightTouchDataGridRow row = contentPresenter.FindChild<LightTouchDataGridRow>(); - if (CollectionFilter != null && row != null) - { - row.Visibility = CollectionFilter.Filter(row.DataContext) ? Visibility.Visible : Visibility.Collapsed; - display = row.Visibility == Visibility.Visible; - } + bool display = true; - if (display) - { - if (AnimateSorting && allowAnimation) + if (CollectionFilter != null && row != null) + { + row.Visibility = CollectionFilter.Filter(row.DataContext) ? Visibility.Visible : Visibility.Collapsed; + display = row.Visibility == Visibility.Visible; + } + + if (display) { - if (double.IsNaN(Canvas.GetTop(contentPresenter))) + if (AnimateSorting && allowAnimation) { - Canvas.SetTop(contentPresenter, current_top); - Canvas.SetLeft(contentPresenter, 0); + if (double.IsNaN(Canvas.GetTop(contentPresenter))) + { + Canvas.SetTop(contentPresenter, current_top); + Canvas.SetLeft(contentPresenter, 0); + } + else + { + int duration = _rnd.Next(200, 500); + + DoubleAnimation aniY = new DoubleAnimation(); + aniY.To = current_top; + aniY.Duration = TimeSpan.FromMilliseconds(duration); + contentPresenter.BeginAnimation(Canvas.TopProperty, aniY); + + DoubleAnimation aniX = new DoubleAnimation(); + aniX.FillBehavior = FillBehavior.Stop; + aniX.To = _rnd.Next(-20, 20); + aniX.AutoReverse = true; + aniX.Duration = TimeSpan.FromMilliseconds(duration / 2); + contentPresenter.BeginAnimation(Canvas.LeftProperty, aniX, HandoffBehavior.SnapshotAndReplace); + } } else { - int duration = _rnd.Next(200, 500); + if (AnimateSorting) + { + contentPresenter.BeginAnimation(Canvas.TopProperty, null); + } - DoubleAnimation aniY = new DoubleAnimation(); - aniY.To = current_top; - aniY.Duration = TimeSpan.FromMilliseconds(duration); - contentPresenter.BeginAnimation(Canvas.TopProperty, aniY); - - DoubleAnimation aniX = new DoubleAnimation(); - aniX.FillBehavior = FillBehavior.Stop; - aniX.To = _rnd.Next(-20, 20); - aniX.AutoReverse = true; - aniX.Duration = TimeSpan.FromMilliseconds(duration / 2); - contentPresenter.BeginAnimation(Canvas.LeftProperty, aniX, HandoffBehavior.SnapshotAndReplace); + Canvas.SetTop(contentPresenter, current_top); + Canvas.SetLeft(contentPresenter, 0); } - } - else - { - if (AnimateSorting) + + if (row != null) { - contentPresenter.BeginAnimation(Canvas.TopProperty, null); + current_top += (row.Margin.Top + row.ActualHeight + row.Margin.Bottom); } - Canvas.SetTop(contentPresenter, current_top); - Canvas.SetLeft(contentPresenter, 0); - } - - if (row != null) - { - current_top += (row.Margin.Top + row.ActualHeight + row.Margin.Bottom); - } - - if (row != null && row.Tag == null) - { - row.RegisterForPreviewMouseOrTouchUp(OnRowMouseTouchUp); - row.RegisterForPreviewMouseOrTouchDown(OnRowMouseTouchDown); - row.Tag = 1; + if (row != null && row.Tag == null) + { + row.RegisterForPreviewMouseOrTouchUp(OnRowMouseTouchUp); + row.RegisterForPreviewMouseOrTouchDown(OnRowMouseTouchDown); + row.Tag = 1; + } } } + catch (Exception ex) + { + Debug.WriteLine(ex); + } } _items_control_rows.Height = current_top; |
