1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Implemented surface config loading/saving/activating

This commit is contained in:
Robert Beekman 2019-10-22 22:52:02 +02:00
parent 91cd23dadf
commit 7cd8bc246c
8 changed files with 210 additions and 134 deletions

View File

@ -7,7 +7,7 @@ namespace Artemis.Core.Models.Surface
{ {
internal SurfaceConfiguration(string name) internal SurfaceConfiguration(string name)
{ {
SurfaceEntity = new SurfaceEntity(); SurfaceEntity = new SurfaceEntity {SurfacePositions = new List<SurfacePositionEntity>()};
Guid = System.Guid.NewGuid().ToString(); Guid = System.Guid.NewGuid().ToString();
Name = name; Name = name;

View File

@ -48,7 +48,7 @@ namespace Artemis.Core.Models.Surface
internal SurfacePositionEntity PositionEntity { get; set; } internal SurfacePositionEntity PositionEntity { get; set; }
internal string Guid { get; } internal string Guid { get; }
public IRGBDevice Device { get; private set; } public IRGBDevice Device { get; internal set; }
public int DeviceId { get; } public int DeviceId { get; }
public string DeviceName { get; } public string DeviceName { get; }
public string DeviceModel { get; } public string DeviceModel { get; }
@ -66,7 +66,10 @@ namespace Artemis.Core.Models.Surface
/// </summary> /// </summary>
public void ApplyToDevice() public void ApplyToDevice()
{ {
Device.Location = new Point(X, Y); if (Device != null)
{
Device.Location = new Point(X, Y);
}
} }
/// <summary> /// <summary>

View File

@ -41,18 +41,39 @@ namespace Artemis.Core.Services.Storage
return; return;
_activeSurfaceConfiguration = value; _activeSurfaceConfiguration = value;
lock (_surfaceConfigurations)
{
// Mark only the new value as active
foreach (var surfaceConfiguration in _surfaceConfigurations)
surfaceConfiguration.IsActive = false;
_activeSurfaceConfiguration.IsActive = true;
// Mark only the new value as active SaveToRepository(_surfaceConfigurations, true);
foreach (var surfaceConfiguration in _surfaceConfigurations) }
surfaceConfiguration.IsActive = false;
_activeSurfaceConfiguration.IsActive = true; // Apply the active surface configuration to the devices
if (ActiveSurfaceConfiguration != null)
{
foreach (var deviceConfiguration in ActiveSurfaceConfiguration.DeviceConfigurations)
deviceConfiguration.ApplyToDevice();
}
// Update the RGB service's graphics decorator to work with the new surface configuration
_rgbService.GraphicsDecorator.UpdateBitmap();
SaveToRepository(_surfaceConfigurations, true);
OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(_activeSurfaceConfiguration)); OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(_activeSurfaceConfiguration));
} }
} }
public ReadOnlyCollection<SurfaceConfiguration> SurfaceConfigurations => _surfaceConfigurations.AsReadOnly(); public ReadOnlyCollection<SurfaceConfiguration> SurfaceConfigurations
{
get
{
lock (_surfaceConfigurations)
{
return _surfaceConfigurations.AsReadOnly();
}
}
}
public SurfaceConfiguration CreateSurfaceConfiguration(string name) public SurfaceConfiguration CreateSurfaceConfiguration(string name)
{ {
@ -66,9 +87,12 @@ namespace Artemis.Core.Services.Storage
configuration.DeviceConfigurations.Add(new SurfaceDeviceConfiguration(rgbDevice, deviceId, configuration)); configuration.DeviceConfigurations.Add(new SurfaceDeviceConfiguration(rgbDevice, deviceId, configuration));
} }
_surfaceRepository.Add(configuration.SurfaceEntity); lock (_surfaceConfigurations)
SaveToRepository(configuration, true); {
return configuration; _surfaceRepository.Add(configuration.SurfaceEntity);
SaveToRepository(configuration, true);
return configuration;
}
} }
public void DeleteSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration) public void DeleteSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration)
@ -76,20 +100,28 @@ namespace Artemis.Core.Services.Storage
if (surfaceConfiguration == ActiveSurfaceConfiguration) if (surfaceConfiguration == ActiveSurfaceConfiguration)
throw new ArtemisCoreException($"Cannot delete surface configuration '{surfaceConfiguration.Name}' because it is active."); throw new ArtemisCoreException($"Cannot delete surface configuration '{surfaceConfiguration.Name}' because it is active.");
surfaceConfiguration.Destroy(); lock (_surfaceConfigurations)
_surfaceConfigurations.Remove(surfaceConfiguration); {
surfaceConfiguration.Destroy();
_surfaceConfigurations.Remove(surfaceConfiguration);
_surfaceRepository.Remove(surfaceConfiguration.SurfaceEntity); _surfaceRepository.Remove(surfaceConfiguration.SurfaceEntity);
_surfaceRepository.Save(); _surfaceRepository.Save();
}
} }
#region Event handlers #region Event handlers
private void RgbServiceOnDeviceLoaded(object sender, DeviceEventArgs e) private void RgbServiceOnDeviceLoaded(object sender, DeviceEventArgs e)
{ {
// Match the newly loaded device with the current config lock (_surfaceConfigurations)
if (ActiveSurfaceConfiguration != null) {
MatchDeviceConfiguration(e.Device, ActiveSurfaceConfiguration); foreach (var surfaceConfiguration in _surfaceConfigurations)
MatchDeviceConfiguration(e.Device, surfaceConfiguration);
}
foreach (var deviceConfiguration in ActiveSurfaceConfiguration.DeviceConfigurations)
deviceConfiguration.ApplyToDevice();
} }
#endregion #endregion
@ -108,7 +140,10 @@ namespace Artemis.Core.Services.Storage
foreach (var rgbDevice in devices) foreach (var rgbDevice in devices)
MatchDeviceConfiguration(rgbDevice, surfaceConfiguration); MatchDeviceConfiguration(rgbDevice, surfaceConfiguration);
// Finally, add the surface config to the collection // Finally, add the surface config to the collection
_surfaceConfigurations.Add(surfaceConfiguration); lock (_surfaceConfigurations)
{
_surfaceConfigurations.Add(surfaceConfiguration);
}
} }
// When all surface configs are loaded, apply the active surface config // When all surface configs are loaded, apply the active surface config
@ -163,6 +198,7 @@ namespace Artemis.Core.Services.Storage
surfaceConfiguration.DeviceConfigurations.Add(deviceConfig); surfaceConfiguration.DeviceConfigurations.Add(deviceConfig);
} }
deviceConfig.Device = rgbDevice;
deviceConfig.ApplyToDevice(); deviceConfig.ApplyToDevice();
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Artemis.Core.Models.Surface;
using RGB.NET.Core; using RGB.NET.Core;
using Stylet; using Stylet;
using Point = System.Windows.Point; using Point = System.Windows.Point;
@ -14,39 +15,56 @@ namespace Artemis.UI.ViewModels.Controls.SurfaceEditor
private double _dragOffsetY; private double _dragOffsetY;
private readonly List<SurfaceLedViewModel> _leds; private readonly List<SurfaceLedViewModel> _leds;
public SurfaceDeviceViewModel(IRGBDevice device) public SurfaceDeviceViewModel(SurfaceDeviceConfiguration deviceConfiguration)
{ {
Device = device; DeviceConfiguration = deviceConfiguration;
_leds = new List<SurfaceLedViewModel>(); _leds = new List<SurfaceLedViewModel>();
foreach (var led in Device) if (DeviceConfiguration.Device != null)
_leds.Add(new SurfaceLedViewModel(led)); {
foreach (var led in DeviceConfiguration.Device)
_leds.Add(new SurfaceLedViewModel(led));
}
} }
public IRGBDevice Device { get; } public SurfaceDeviceConfiguration DeviceConfiguration { get; }
public SelectionStatus SelectionStatus { get; set; } public SelectionStatus SelectionStatus { get; set; }
public Cursor Cursor { get; set; } public Cursor Cursor { get; set; }
public int ZIndex { get; set; }
public double X
{
get => DeviceConfiguration.X;
set => DeviceConfiguration.X = value;
}
public double Y
{
get => DeviceConfiguration.Y;
set => DeviceConfiguration.Y = value;
}
public int ZIndex
{
get => DeviceConfiguration.ZIndex;
set => DeviceConfiguration.ZIndex = value;
}
public IReadOnlyCollection<SurfaceLedViewModel> Leds => _leds.AsReadOnly(); public IReadOnlyCollection<SurfaceLedViewModel> Leds => _leds.AsReadOnly();
public Rect DeviceRectangle => new Rect(Device.Location.X, Device.Location.Y, Device.Size.Width, Device.Size.Height);
public Rect DeviceRectangle => new Rect(X, Y, DeviceConfiguration.Device.Size.Width, DeviceConfiguration.Device.Size.Height);
public void StartMouseDrag(Point mouseStartPosition) public void StartMouseDrag(Point mouseStartPosition)
{ {
_dragOffsetX = Device.Location.X - mouseStartPosition.X; _dragOffsetX = X - mouseStartPosition.X;
_dragOffsetY = Device.Location.Y - mouseStartPosition.Y; _dragOffsetY = Y - mouseStartPosition.Y;
} }
public void UpdateMouseDrag(Point mousePosition) public void UpdateMouseDrag(Point mousePosition)
{ {
var roundedX = Math.Round((mousePosition.X + _dragOffsetX) / 10, 0, MidpointRounding.AwayFromZero) * 10; var roundedX = Math.Round((mousePosition.X + _dragOffsetX) / 10, 0, MidpointRounding.AwayFromZero) * 10;
var roundedY = Math.Round((mousePosition.Y + _dragOffsetY) / 10, 0, MidpointRounding.AwayFromZero) * 10; var roundedY = Math.Round((mousePosition.Y + _dragOffsetY) / 10, 0, MidpointRounding.AwayFromZero) * 10;
Device.Location = new RGB.NET.Core.Point(roundedX, roundedY); X = roundedX;
} Y = roundedY;
public void FinishMouseDrag(Point mouseEndPosition)
{
// TODO: Save and update
} }
// ReSharper disable once UnusedMember.Global - Called from view // ReSharper disable once UnusedMember.Global - Called from view

View File

@ -1,5 +1,4 @@
using System; using RGB.NET.Core;
using RGB.NET.Core;
using Stylet; using Stylet;
namespace Artemis.UI.ViewModels.Controls.SurfaceEditor namespace Artemis.UI.ViewModels.Controls.SurfaceEditor
@ -9,29 +8,18 @@ namespace Artemis.UI.ViewModels.Controls.SurfaceEditor
public SurfaceLedViewModel(Led led) public SurfaceLedViewModel(Led led)
{ {
Led = led; Led = led;
Update();
X = Led.LedRectangle.X;
Y = Led.LedRectangle.Y;
Width = Led.LedRectangle.Width;
Height = Led.LedRectangle.Height;
} }
public Led Led { get; } public Led Led { get; }
public double X { get; private set; } public double X { get; }
public double Y { get; private set; } public double Y { get; }
public double Width { get; private set; } public double Width { get; }
public double Height { get; private set; } public double Height { get; }
public void Update()
{
if (Math.Abs(Led.LedRectangle.X - X) > 0.1)
X = Led.LedRectangle.X;
if (Math.Abs(Led.LedRectangle.Y - Y) > 0.1)
Y = Led.LedRectangle.Y;
if (Math.Abs(Led.LedRectangle.Width - Width) > 0.1)
Width = Led.LedRectangle.Width;
if (Math.Abs(Led.LedRectangle.Height - Height) > 0.1)
Height = Led.LedRectangle.Height;
}
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -27,64 +28,31 @@ namespace Artemis.UI.ViewModels.Screens
SurfaceConfigurations = new ObservableCollection<SurfaceConfiguration>(); SurfaceConfigurations = new ObservableCollection<SurfaceConfiguration>();
SelectionRectangle = new RectangleGeometry(); SelectionRectangle = new RectangleGeometry();
PanZoomViewModel = new PanZoomViewModel(); PanZoomViewModel = new PanZoomViewModel();
_rgbService = rgbService; _rgbService = rgbService;
_surfaceService = surfaceService; _surfaceService = surfaceService;
_rgbService.DeviceLoaded += RgbServiceOnDeviceLoaded;
foreach (var surfaceDevice in _rgbService.LoadedDevices)
{
var device = new SurfaceDeviceViewModel(surfaceDevice) {Cursor = Cursors.Hand};
Devices.Add(device);
device.ZIndex = Devices.IndexOf(device) + 1;
}
} }
public RectangleGeometry SelectionRectangle { get; set; } public RectangleGeometry SelectionRectangle { get; set; }
public ObservableCollection<SurfaceDeviceViewModel> Devices { get; set; } public ObservableCollection<SurfaceDeviceViewModel> Devices { get; set; }
public SurfaceConfiguration SelectedSurfaceConfiguration { get; set; } public SurfaceConfiguration SelectedSurfaceConfiguration
{
get => _selectedSurfaceConfiguration;
set
{
_selectedSurfaceConfiguration = value;
ApplySelectedSurfaceConfiguration();
}
}
public ObservableCollection<SurfaceConfiguration> SurfaceConfigurations { get; set; } public ObservableCollection<SurfaceConfiguration> SurfaceConfigurations { get; set; }
public string NewConfigurationName { get; set; } public string NewConfigurationName { get; set; }
public PanZoomViewModel PanZoomViewModel { get; set; } public PanZoomViewModel PanZoomViewModel { get; set; }
public string Title => "Surface Editor"; public string Title => "Surface Editor";
private void RgbServiceOnDeviceLoaded(object sender, DeviceEventArgs e)
{
Execute.OnUIThread(() =>
{
if (Devices.All(d => d.Device != e.Device))
{
var device = new SurfaceDeviceViewModel(e.Device) {Cursor = Cursors.Hand};
Devices.Add(device);
device.ZIndex = Devices.IndexOf(device) + 1;
}
});
}
private async Task LoadSurfaceConfigurations()
{
await Execute.OnUIThreadAsync(async () =>
{
SurfaceConfigurations.Clear();
// Get surface configs
var configs = await _surfaceService.GetSurfaceConfigurationsAsync();
// Populate the UI collection
foreach (var surfaceConfiguration in configs)
SurfaceConfigurations.Add(surfaceConfiguration);
// Select either the first active surface or the first available surface
SelectedSurfaceConfiguration = SurfaceConfigurations.FirstOrDefault(s => s.IsActive) ?? SurfaceConfigurations.FirstOrDefault();
// Create a default if there is none
if (SelectedSurfaceConfiguration == null)
SelectedSurfaceConfiguration = AddSurfaceConfiguration("Default");
});
}
public SurfaceConfiguration AddSurfaceConfiguration(string name) public SurfaceConfiguration AddSurfaceConfiguration(string name)
{ {
var config = _surfaceService.CreateSurfaceConfiguration(name); var config = _surfaceService.CreateSurfaceConfiguration(name);
@ -92,6 +60,65 @@ namespace Artemis.UI.ViewModels.Screens
return config; return config;
} }
private void LoadSurfaceConfigurations()
{
// Get surface configs
var configs = _surfaceService.SurfaceConfigurations;
// Get the active config, if empty, create a default config
var activeConfig = _surfaceService.ActiveSurfaceConfiguration;
if (activeConfig == null)
{
activeConfig = AddSurfaceConfiguration("Default");
_surfaceService.ActiveSurfaceConfiguration = activeConfig;
}
Execute.OnUIThread(() =>
{
// Populate the UI collection
SurfaceConfigurations.Clear();
foreach (var surfaceConfiguration in configs)
SurfaceConfigurations.Add(surfaceConfiguration);
// Set the active config
SelectedSurfaceConfiguration = activeConfig;
});
}
private void ApplySelectedSurfaceConfiguration()
{
if (SelectedSurfaceConfiguration == null)
{
Execute.OnUIThread(Devices.Clear);
return;
}
Task.Run(() =>
{
// Create VMs for the new config outside the UI thread
var viewModels = SelectedSurfaceConfiguration.DeviceConfigurations.Select(c => new SurfaceDeviceViewModel(c)).ToList();
// Commit the VMs to the view
Execute.OnUIThread(() =>
{
Devices.Clear();
foreach (var viewModel in viewModels.OrderBy(v => v.ZIndex))
Devices.Add(viewModel);
});
});
}
#region Overrides of Screen
protected override void OnActivate()
{
LoadSurfaceConfigurations();
base.OnActivate();
}
#endregion
#region Configuration management
public void ConfirmationDialogClosing() public void ConfirmationDialogClosing()
{ {
if (!string.IsNullOrWhiteSpace(NewConfigurationName)) if (!string.IsNullOrWhiteSpace(NewConfigurationName))
@ -103,14 +130,6 @@ namespace Artemis.UI.ViewModels.Screens
NewConfigurationName = null; NewConfigurationName = null;
} }
#region Overrides of Screen
protected override void OnActivate()
{
Task.Run(LoadSurfaceConfigurations);
base.OnActivate();
}
#endregion #endregion
#region Context menu actions #region Context menu actions
@ -166,6 +185,7 @@ namespace Artemis.UI.ViewModels.Screens
private MouseDragStatus _mouseDragStatus; private MouseDragStatus _mouseDragStatus;
private Point _mouseDragStartPoint; private Point _mouseDragStartPoint;
private SurfaceConfiguration _selectedSurfaceConfiguration;
// ReSharper disable once UnusedMember.Global - Called from view // ReSharper disable once UnusedMember.Global - Called from view
public void EditorGridMouseClick(object sender, MouseEventArgs e) public void EditorGridMouseClick(object sender, MouseEventArgs e)
@ -251,6 +271,12 @@ namespace Artemis.UI.ViewModels.Screens
device.SelectionStatus = SelectionStatus.None; device.SelectionStatus = SelectionStatus.None;
} }
} }
else
{
foreach (var device in Devices)
device.DeviceConfiguration.ApplyToDevice();
_surfaceService.SaveToRepository(SelectedSurfaceConfiguration, true);
}
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
_mouseDragStatus = MouseDragStatus.None; _mouseDragStatus = MouseDragStatus.None;
@ -281,7 +307,7 @@ namespace Artemis.UI.ViewModels.Screens
foreach (var device in Devices.Where(d => d.SelectionStatus == SelectionStatus.Selected)) foreach (var device in Devices.Where(d => d.SelectionStatus == SelectionStatus.Selected))
device.UpdateMouseDrag(position); device.UpdateMouseDrag(position);
} }
#endregion #endregion
#region Panning and zooming #region Panning and zooming

View File

@ -13,19 +13,19 @@
Cursor="{Binding Cursor}" Cursor="{Binding Cursor}"
MouseEnter="{s:Action MouseEnter}" MouseEnter="{s:Action MouseEnter}"
MouseLeave="{s:Action MouseLeave}" MouseLeave="{s:Action MouseLeave}"
ToolTip="{Binding Device.DeviceInfo.DeviceName}"> ToolTip="{Binding DeviceConfiguration.Device.DeviceInfo.DeviceName}">
<UserControl.Resources> <UserControl.Resources>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" /> <converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid>
<Image Source="{Binding Device.DeviceInfo.Image}" /> <Image Source="{Binding DeviceConfiguration.Device.DeviceInfo.Image}" />
<Rectangle Fill="{DynamicResource ControlBackgroundBrush}" <Rectangle Fill="{DynamicResource ControlBackgroundBrush}"
Stroke="{DynamicResource ControlBorderBrush}" Stroke="{DynamicResource ControlBorderBrush}"
StrokeThickness="1" StrokeThickness="1"
Visibility="{Binding Device.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}" /> Visibility="{Binding DeviceConfiguration.Device.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock Text="{Binding Device.DeviceInfo.DeviceName}" <TextBlock Text="{Binding DeviceConfiguration.Device.DeviceInfo.DeviceName}"
Visibility="{Binding Device.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}" Visibility="{Binding DeviceConfiguration.Device.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
TextWrapping="Wrap" TextWrapping="Wrap"

View File

@ -33,7 +33,8 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource MaterialDesignDisplay1TextBlock}">Surface layout</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource MaterialDesignDisplay1TextBlock}">Surface layout</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignCaptionTextBlock}" Margin="0,0,0,5"> <TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignCaptionTextBlock}"
Margin="0,0,0,5">
The surface is a digital representation of your LED setup. Set this up accurately and effects will seamlessly move from one device to the other. The surface is a digital representation of your LED setup. Set this up accurately and effects will seamlessly move from one device to the other.
</TextBlock> </TextBlock>
@ -47,7 +48,8 @@
MouseDown="{s:Action EditorGridMouseClick}" MouseDown="{s:Action EditorGridMouseClick}"
MouseMove="{s:Action EditorGridMouseMove}"> MouseMove="{s:Action EditorGridMouseMove}">
<Grid.Background> <Grid.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute"> <VisualBrush TileMode="Tile" Stretch="Uniform"
Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute">
<VisualBrush.Visual> <VisualBrush.Visual>
<Grid Width="20" Height="20"> <Grid Width="20" Height="20">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -87,7 +89,8 @@
<Grid Name="EditorDisplayGrid"> <Grid Name="EditorDisplayGrid">
<Grid.RenderTransform> <Grid.RenderTransform>
<TransformGroup> <TransformGroup>
<ScaleTransform ScaleX="{Binding PanZoomViewModel.Zoom}" ScaleY="{Binding PanZoomViewModel.Zoom}" /> <ScaleTransform ScaleX="{Binding PanZoomViewModel.Zoom}"
ScaleY="{Binding PanZoomViewModel.Zoom}" />
<TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" /> <TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" />
</TransformGroup> </TransformGroup>
</Grid.RenderTransform> </Grid.RenderTransform>
@ -99,14 +102,15 @@
</ItemsControl.ItemsPanel> </ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle> <ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter"> <Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Device.Location.X}" /> <Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Device.Location.Y}" /> <Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style> </Style>
</ItemsControl.ItemContainerStyle> </ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<ContentControl Width="{Binding Device.Size.Width}" <ContentControl Width="{Binding DeviceConfiguration.Device.Size.Width}"
Height="{Binding Device.Size.Height}" s:View.Model="{Binding }"> Height="{Binding DeviceConfiguration.Device.Size.Height}"
s:View.Model="{Binding}">
<ContentControl.ContextMenu> <ContentControl.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" <MenuItem Header="Bring to Front" Command="{s:Action BringToFront}"
@ -144,7 +148,7 @@
<!-- Multi-selection rectangle --> <!-- Multi-selection rectangle -->
<Path Data="{Binding SelectionRectangle}" Opacity="0" <Path Data="{Binding SelectionRectangle}" Opacity="0"
Stroke="{DynamicResource PrimaryHueLightBrush}" Stroke="{DynamicResource PrimaryHueLightBrush}"
StrokeThickness="1" StrokeThickness="1"
Name="MultiSelectionPath" Name="MultiSelectionPath"
IsHitTestVisible="False"> IsHitTestVisible="False">
<Path.Fill> <Path.Fill>
@ -163,7 +167,7 @@
Value="{Binding PanZoomViewModel.ZoomPercentage}" Value="{Binding PanZoomViewModel.ZoomPercentage}"
Style="{StaticResource MaterialDesignDiscreteSlider}" /> Style="{StaticResource MaterialDesignDiscreteSlider}" />
<Button Command="{s:Action ResetZoomAndPan}" <Button Command="{s:Action ResetZoomAndPan}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
ToolTip="Reset zoom &amp; position"> ToolTip="Reset zoom &amp; position">
<materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" /> <materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" />
@ -171,7 +175,7 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
</materialDesign:Card> </materialDesign:Card>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="2" Grid.Column="1" <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="2" Grid.Column="1"
VerticalAlignment="Stretch" Margin="5,0,0,0"> VerticalAlignment="Stretch" Margin="5,0,0,0">
<materialDesign:DialogHost DialogClosing="{s:Action ConfirmationDialogClosing}"> <materialDesign:DialogHost DialogClosing="{s:Action ConfirmationDialogClosing}">
@ -208,7 +212,7 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListBox Grid.Row="0" ItemsSource="{Binding SurfaceConfigurations}"> <ListBox Grid.Row="0" ItemsSource="{Binding SurfaceConfigurations}" SelectedItem="{Binding SelectedSurfaceConfiguration}">
<ListBox.Resources> <ListBox.Resources>
<DataTemplate DataType="{x:Type models:SurfaceConfiguration}"> <DataTemplate DataType="{x:Type models:SurfaceConfiguration}">
<TextBlock Text="{Binding Name}" ToolTip="{Binding Name}" /> <TextBlock Text="{Binding Name}" ToolTip="{Binding Name}" />
@ -241,12 +245,13 @@
</materialDesign:DialogHost> </materialDesign:DialogHost>
</materialDesign:Card> </materialDesign:Card>
<TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignCaptionTextBlock}" Margin="0,5,0,0"> <TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
<Run Text="Hold"/> Style="{StaticResource MaterialDesignCaptionTextBlock}" Margin="0,5,0,0">
<Run FontWeight="Bold" Text="shift"/> <Run Text="Hold" />
<Run Text="or click and drag to select multiple devices at once. To move around the surface hold down"/> <Run FontWeight="Bold" Text="shift" />
<Run FontWeight="Bold" Text="ctrl"/> <Run Text="or click and drag to select multiple devices at once. To move around the surface hold down" />
<Run Text="and drag."/> <Run FontWeight="Bold" Text="ctrl" />
<Run Text="and drag." />
</TextBlock> </TextBlock>
</Grid> </Grid>
</UserControl> </UserControl>