1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-02 02:33:32 +00:00

Broke the surface editor

Added device properties to surface editor though!
This commit is contained in:
Robert 2019-11-21 19:09:50 +01:00
parent 086f2fc1f9
commit 240efb2907
20 changed files with 444 additions and 79 deletions

View File

@ -63,12 +63,18 @@ namespace Artemis.Core.Models.Surface
set => DeviceEntity.Rotation = value; set => DeviceEntity.Rotation = value;
} }
public double Scale
{
get => DeviceEntity.Scale;
set => DeviceEntity.Scale = value;
}
public int ZIndex public int ZIndex
{ {
get => DeviceEntity.ZIndex; get => DeviceEntity.ZIndex;
set => DeviceEntity.ZIndex = value; set => DeviceEntity.ZIndex = value;
} }
internal void ApplyToEntity() internal void ApplyToEntity()
{ {
// Other properties are computed // Other properties are computed
@ -79,8 +85,10 @@ namespace Artemis.Core.Models.Surface
{ {
RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y); RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y);
RgbDevice.Rotation = DeviceEntity.Rotation; RgbDevice.Rotation = DeviceEntity.Rotation;
RgbDevice.Scale = DeviceEntity.Scale;
CalculateRenderProperties(); CalculateRenderProperties();
OnDeviceUpdated();
} }
internal void CalculateRenderProperties() internal void CalculateRenderProperties()
@ -103,10 +111,16 @@ namespace Artemis.Core.Models.Surface
path.FillMode = FillMode.Winding; path.FillMode = FillMode.Winding;
RenderPath = path; RenderPath = path;
} }
public override string ToString() public override string ToString()
{ {
return $"[{RgbDevice.DeviceInfo.DeviceType}] {RgbDevice.DeviceInfo.DeviceName} - {X}.{Y}.{ZIndex}"; return $"[{RgbDevice.DeviceInfo.DeviceType}] {RgbDevice.DeviceInfo.DeviceName} - {X}.{Y}.{ZIndex}";
} }
public event EventHandler DeviceUpdated;
protected virtual void OnDeviceUpdated()
{
DeviceUpdated?.Invoke(this, EventArgs.Empty);
}
} }
} }

View File

@ -10,6 +10,7 @@ namespace Artemis.Storage.Entities.Surface
public double X { get; set; } public double X { get; set; }
public double Y { get; set; } public double Y { get; set; }
public double Rotation { get; set; } public double Rotation { get; set; }
public double Scale { get; set; }
public int ZIndex { get; set; } public int ZIndex { get; set; }
} }
} }

View File

@ -17,19 +17,17 @@
<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/Fonts.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/Colors.xaml" />
<ResourceDictionary <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<!-- Material Design --> <!-- Material Design -->
<ResourceDictionary <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Teal.xaml" />
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Teal.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Teal.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Teal.xaml" />
<!-- Material Design: MahApps Compatibility -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.NumericUpDown.xaml" />
<!-- Include the Dragablz Material Design style --> <!-- Include the Dragablz Material Design style -->
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml" /> <ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>

View File

@ -170,6 +170,8 @@
<Compile Include="Screens\Module\ProfileEditor\ProfileEditorPanelViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\ProfileEditorPanelViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileViewModel.cs" />
<Compile Include="Screens\News\NewsViewModel.cs" /> <Compile Include="Screens\News\NewsViewModel.cs" />
<Compile Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigViewModelValidator.cs" />
<Compile Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigViewModel.cs" />
<Compile Include="Screens\Workshop\WorkshopViewModel.cs" /> <Compile Include="Screens\Workshop\WorkshopViewModel.cs" />
<Compile Include="Services\Dialog\DialogService.cs" /> <Compile Include="Services\Dialog\DialogService.cs" />
<Compile Include="Services\Interfaces\IDialogService.cs" /> <Compile Include="Services\Interfaces\IDialogService.cs" />
@ -245,6 +247,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\SurfaceEditor\Visualization\SurfaceLedView.xaml"> <Page Include="Screens\SurfaceEditor\Visualization\SurfaceLedView.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@ -352,7 +358,18 @@
<ItemGroup> <ItemGroup>
<Resource Include="logo-512.ico" /> <Resource Include="logo-512.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<None Include="Resources\aero_rotate_tl.cur" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\aero_rotate_tr.cur" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\aero_rotate_bl.cur" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\aero_rotate_br.cur" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent> <PostBuildEvent>

View File

@ -60,6 +60,46 @@ namespace Artemis.UI.Properties {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] aero_rotate_bl {
get {
object obj = ResourceManager.GetObject("aero_rotate_bl", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] aero_rotate_br {
get {
object obj = ResourceManager.GetObject("aero_rotate_br", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] aero_rotate_tl {
get {
object obj = ResourceManager.GetObject("aero_rotate_tl", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] aero_rotate_tr {
get {
object obj = ResourceManager.GetObject("aero_rotate_tr", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[]. /// Looks up a localized resource of type System.Byte[].
/// </summary> /// </summary>

View File

@ -118,6 +118,18 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="aero_rotate_bl" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\aero_rotate_bl.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="aero_rotate_br" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\aero_rotate_br.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="aero_rotate_tl" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\aero_rotate_tl.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="aero_rotate_tr" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\aero_rotate_tr.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="bow" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="bow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bow.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\bow.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -46,7 +46,6 @@ namespace Artemis.UI.Screens.Shared
{ {
if (e.LeftButton == MouseButtonState.Released) if (e.LeftButton == MouseButtonState.Released)
{ {
Mouse.OverrideCursor = Cursors.Arrow;
_lastPanPosition = null; _lastPanPosition = null;
return; return;
} }

View File

@ -7,7 +7,7 @@
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="213.053" d:DesignWidth="254.425"> d:DesignHeight="213.053" d:DesignWidth="254.425">
<StackPanel Margin="16"> <StackPanel Margin="16" UseLayoutRounding="True">
<TextBlock> <TextBlock>
Add a new surface layout Add a new surface layout
</TextBlock> </TextBlock>

View File

@ -0,0 +1,71 @@
<UserControl x:Class="Artemis.UI.Screens.SurfaceEditor.Dialogs.SurfaceDeviceConfigView"
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:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Dialogs"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="351.305" d:DesignWidth="262.163"
d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceDeviceConfigViewModel}}">
<StackPanel Margin="16" UseLayoutRounding="True">
<TextBlock Text="{Binding Title}" Style="{StaticResource MaterialDesignTitleTextBlock}" />
<Label>X-coordinate</Label>
<mah:NumericUpDown materialDesign:HintAssist.Hint="X-coordinate"
Value="{Binding X}"
Style="{StaticResource MaterialDesignNumericUpDown}"
Minimum="0"
Interval="1"
StringFormat="0" />
<Label>Y-coordinate</Label>
<mah:NumericUpDown materialDesign:HintAssist.Hint="Y-coordinate"
Value="{Binding Y}"
Style="{StaticResource MaterialDesignNumericUpDown}"
Minimum="0"
Interval="1"
StringFormat="0" />
<Label>Scale</Label>
<mah:NumericUpDown materialDesign:HintAssist.Hint="Scale"
Value="{Binding Scale}"
Style="{StaticResource MaterialDesignNumericUpDown}"
Minimum="0"
Interval="0.1"
StringFormat="0.00" />
<Label>Rotation</Label>
<mah:NumericUpDown materialDesign:HintAssist.Hint="Rotation"
Value="{Binding Rotation}"
Style="{StaticResource MaterialDesignNumericUpDown}"
Minimum="0"
Maximum="359"
Interval="1"
StringFormat="0" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0"
Command="{s:Action Cancel}">
<Button.CommandParameter>
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
False
</system:Boolean>
</Button.CommandParameter>
CANCEL
</Button>
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 8 0"
Command="{s:Action Accept}">
<Button.CommandParameter>
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
True
</system:Boolean>
</Button.CommandParameter>
APPLY
</Button>
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,49 @@
using System.Threading.Tasks;
using Artemis.UI.Screens.SurfaceEditor.Visualization;
using Artemis.UI.ViewModels.Dialogs;
using Stylet;
namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
{
public class SurfaceDeviceConfigViewModel : DialogViewModelBase
{
public SurfaceDeviceConfigViewModel(SurfaceDeviceViewModel surfaceDeviceViewModel, IModelValidator<SurfaceDeviceConfigViewModel> validator)
: base(validator)
{
SurfaceDeviceViewModel = surfaceDeviceViewModel;
Title = $"{SurfaceDeviceViewModel.Device.RgbDevice.DeviceInfo.DeviceName} - Properties";
X = (int) SurfaceDeviceViewModel.Device.X;
Y = (int) SurfaceDeviceViewModel.Device.Y;
Scale = SurfaceDeviceViewModel.Device.Scale;
Rotation = (int) SurfaceDeviceViewModel.Device.Rotation;
}
public SurfaceDeviceViewModel SurfaceDeviceViewModel { get; }
public string Title { get; set; }
public int X { get; set; }
public int Y { get; set; }
public double Scale { get; set; }
public int Rotation { get; set; }
public async Task Accept()
{
await ValidateAsync();
if (HasErrors)
return;
SurfaceDeviceViewModel.Device.X = X;
SurfaceDeviceViewModel.Device.Y = Y;
SurfaceDeviceViewModel.Device.Scale = Scale;
SurfaceDeviceViewModel.Device.Rotation = Rotation;
Session.Close(true);
}
public async Task Cancel()
{
Session.Close(false);
}
}
}

View File

@ -0,0 +1,19 @@
using FluentValidation;
namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
{
public class SurfaceDeviceConfigViewModelValidator : AbstractValidator<SurfaceDeviceConfigViewModel>
{
public SurfaceDeviceConfigViewModelValidator()
{
RuleFor(m => m.X).GreaterThanOrEqualTo(0).WithMessage("X-coordinate must be 0 or greater");
RuleFor(m => m.Y).GreaterThanOrEqualTo(0).WithMessage("Y-coordinate must be 0 or greater");
RuleFor(m => m.Scale).GreaterThanOrEqualTo(0.2).WithMessage("Scale must be 0.2 or greater");
RuleFor(m => m.Rotation).GreaterThanOrEqualTo(0).WithMessage("Rotation must be 0 or greater");
RuleFor(m => m.Rotation).LessThanOrEqualTo(359).WithMessage("Rotation must be 359 or less");
}
}
}

View File

@ -38,14 +38,17 @@
</StackPanel> </StackPanel>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Grid.Column="0" <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Grid.Column="0"
VerticalAlignment="Stretch" Margin="0,0,5,0"> VerticalAlignment="Stretch" Margin="0,0,5,0" >
<Grid ClipToBounds="True" <Grid ClipToBounds="True"
Focusable="True"
FocusVisualStyle="{StaticResource FocusVisual}"
KeyUp="{s:Action EditorGridKeyUp}" KeyUp="{s:Action EditorGridKeyUp}"
KeyDown="{s:Action EditorGridKeyDown}" KeyDown="{s:Action EditorGridKeyDown}"
MouseWheel="{s:Action EditorGridMouseWheel}" MouseWheel="{s:Action EditorGridMouseWheel}"
MouseUp="{s:Action EditorGridMouseClick}" MouseUp="{s:Action EditorGridMouseClick}"
MouseDown="{s:Action EditorGridMouseClick}" MouseDown="{s:Action EditorGridMouseClick}"
MouseMove="{s:Action EditorGridMouseMove}"> MouseMove="{s:Action EditorGridMouseMove}"
Cursor="{Binding Cursor}">
<Grid.Background> <Grid.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" <VisualBrush TileMode="Tile" Stretch="Uniform"
Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute"> Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute">
@ -101,8 +104,8 @@
</ItemsControl.ItemsPanel> </ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle> <ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter"> <Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}" /> <Setter Property="Canvas.Left" Value="{Binding RgbDeviceRectangle.Location.X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" /> <Setter Property="Canvas.Top" Value="{Binding RgbDeviceRectangle.Location.Y}" />
</Style> </Style>
</ItemsControl.ItemContainerStyle> </ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
@ -110,32 +113,37 @@
<ContentControl Width="{Binding Device.RgbDevice.Size.Width}" <ContentControl Width="{Binding Device.RgbDevice.Size.Width}"
Height="{Binding Device.RgbDevice.Size.Height}" Height="{Binding Device.RgbDevice.Size.Height}"
s:View.Model="{Binding}"> s:View.Model="{Binding}">
<ContentControl.RenderTransform>
<RotateTransform Angle="{Binding Device.RgbDevice.Rotation.Degrees}" CenterX="{Binding RgbDeviceRectangle.Center.X}" CenterY="{Binding RgbDeviceRectangle.Center.Y}"></RotateTransform>
</ContentControl.RenderTransform>
<ContentControl.ContextMenu> <ContentControl.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" <MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" CommandParameter="{Binding}">
CommandParameter="{Binding}">
<MenuItem.Icon> <MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringToFront" /> <materialDesign:PackIcon Kind="ArrangeBringToFront" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Bring Forward" Command="{s:Action BringForward}" <MenuItem Header="Bring Forward" Command="{s:Action BringForward}" CommandParameter="{Binding}">
CommandParameter="{Binding}">
<MenuItem.Icon> <MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringForward" /> <materialDesign:PackIcon Kind="ArrangeBringForward" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Send to Back" Command="{s:Action SendToBack}" <MenuItem Header="Send to Back" Command="{s:Action SendToBack}" CommandParameter="{Binding}">
CommandParameter="{Binding}">
<MenuItem.Icon> <MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendToBack" /> <materialDesign:PackIcon Kind="ArrangeSendToBack" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Send Backward" Command="{s:Action SendBackward}" <MenuItem Header="Send Backward" Command="{s:Action SendBackward}" CommandParameter="{Binding}">
CommandParameter="{Binding}">
<MenuItem.Icon> <MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendBackward" /> <materialDesign:PackIcon Kind="ArrangeSendBackward" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<Separator />
<MenuItem Header="View properties" Command="{s:Action ViewProperties}" CommandParameter="{Binding}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Gear" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu> </ContextMenu>
</ContentControl.ContextMenu> </ContentControl.ContextMenu>
</ContentControl> </ContentControl>
@ -179,8 +187,7 @@
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Grid.Column="2" <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Grid.Column="2"
VerticalAlignment="Stretch" Margin="5,0,0,0"> VerticalAlignment="Stretch" Margin="5,0,0,0">
<materialDesign:DialogHost Identifier="SurfaceListDialogHost" CloseOnClickAway="True" <materialDesign:DialogHost Identifier="SurfaceListDialogHost" CloseOnClickAway="True">
UseLayoutRounding="True">
<Grid HorizontalAlignment="Stretch"> <Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />

View File

@ -1,19 +1,21 @@
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;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.Models; using Artemis.Core.Plugins.Models;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.Core.Services.Storage;
using Artemis.Core.Services.Storage.Interfaces; using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Screens.Shared; using Artemis.UI.Screens.Shared;
using Artemis.UI.Screens.SurfaceEditor.Dialogs; using Artemis.UI.Screens.SurfaceEditor.Dialogs;
using Artemis.UI.Screens.SurfaceEditor.Visualization; using Artemis.UI.Screens.SurfaceEditor.Visualization;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Ninject.Parameters;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.SurfaceEditor namespace Artemis.UI.Screens.SurfaceEditor
@ -30,6 +32,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
SurfaceConfigurations = new ObservableCollection<Surface>(); SurfaceConfigurations = new ObservableCollection<Surface>();
SelectionRectangle = new RectangleGeometry(); SelectionRectangle = new RectangleGeometry();
PanZoomViewModel = new PanZoomViewModel(); PanZoomViewModel = new PanZoomViewModel();
Cursor = null;
_surfaceService = surfaceService; _surfaceService = surfaceService;
_dialogService = dialogService; _dialogService = dialogService;
@ -41,6 +44,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
public RectangleGeometry SelectionRectangle { get; set; } public RectangleGeometry SelectionRectangle { get; set; }
public PanZoomViewModel PanZoomViewModel { get; set; } public PanZoomViewModel PanZoomViewModel { get; set; }
public PluginSetting<GridLength> SurfaceListWidth { get; set; } public PluginSetting<GridLength> SurfaceListWidth { get; set; }
public Cursor Cursor { get; set; }
public Surface SelectedSurface public Surface SelectedSurface
{ {
@ -120,8 +124,8 @@ namespace Artemis.UI.Screens.SurfaceEditor
// Sort the devices by ZIndex // Sort the devices by ZIndex
Execute.OnUIThread(() => Execute.OnUIThread(() =>
{ {
foreach (var device in Devices.OrderBy(d => d.ZIndex).ToList()) foreach (var device in Devices.OrderBy(d => d.Device.ZIndex).ToList())
Devices.Move(Devices.IndexOf(device), device.ZIndex - 1); Devices.Move(Devices.IndexOf(device), device.Device.ZIndex - 1);
}); });
_surfaceService.SetActiveSurfaceConfiguration(SelectedSurface); _surfaceService.SetActiveSurfaceConfiguration(SelectedSurface);
@ -177,7 +181,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
for (var i = 0; i < Devices.Count; i++) for (var i = 0; i < Devices.Count; i++)
{ {
var deviceViewModel = Devices[i]; var deviceViewModel = Devices[i];
deviceViewModel.ZIndex = i + 1; deviceViewModel.Device.ZIndex = i + 1;
} }
} }
@ -190,7 +194,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
for (var i = 0; i < Devices.Count; i++) for (var i = 0; i < Devices.Count; i++)
{ {
var deviceViewModel = Devices[i]; var deviceViewModel = Devices[i];
deviceViewModel.ZIndex = i + 1; deviceViewModel.Device.ZIndex = i + 1;
} }
} }
@ -200,7 +204,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
for (var i = 0; i < Devices.Count; i++) for (var i = 0; i < Devices.Count; i++)
{ {
var deviceViewModel = Devices[i]; var deviceViewModel = Devices[i];
deviceViewModel.ZIndex = i + 1; deviceViewModel.Device.ZIndex = i + 1;
} }
} }
@ -212,10 +216,21 @@ namespace Artemis.UI.Screens.SurfaceEditor
for (var i = 0; i < Devices.Count; i++) for (var i = 0; i < Devices.Count; i++)
{ {
var deviceViewModel = Devices[i]; var deviceViewModel = Devices[i];
deviceViewModel.ZIndex = i + 1; deviceViewModel.Device.ZIndex = i + 1;
} }
} }
public async Task ViewProperties(SurfaceDeviceViewModel surfaceDeviceViewModel)
{
var madeChanges = await _dialogService.ShowDialog<SurfaceDeviceConfigViewModel>(new Dictionary<string, object>
{
{"surfaceDeviceViewModel", surfaceDeviceViewModel}
});
if ((bool) madeChanges)
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
}
#endregion #endregion
#region Selection #region Selection
@ -241,6 +256,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
// ReSharper disable once UnusedMember.Global - Called from view // ReSharper disable once UnusedMember.Global - Called from view
public void EditorGridMouseMove(object sender, MouseEventArgs e) public void EditorGridMouseMove(object sender, MouseEventArgs e)
{ {
((Grid) sender).Focus();
// If holding down Ctrl, pan instead of move/select // If holding down Ctrl, pan instead of move/select
if (IsPanKeyDown()) if (IsPanKeyDown())
{ {
@ -285,12 +301,6 @@ namespace Artemis.UI.Screens.SurfaceEditor
_mouseDragStartPoint = position; _mouseDragStartPoint = position;
} }
// While dragging always show a hand to avoid cursor flicker
if (_mouseDragStatus == MouseDragStatus.Dragging)
Mouse.OverrideCursor = Cursors.Hand;
else
Mouse.OverrideCursor = Cursors.Arrow;
// Any time dragging starts, start with a new rect // Any time dragging starts, start with a new rect
SelectionRectangle.Rect = new Rect(); SelectionRectangle.Rect = new Rect();
} }
@ -311,7 +321,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
else else
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
Mouse.OverrideCursor = null;
_mouseDragStatus = MouseDragStatus.None; _mouseDragStatus = MouseDragStatus.None;
} }
@ -353,13 +363,13 @@ namespace Artemis.UI.Screens.SurfaceEditor
public void EditorGridKeyDown(object sender, KeyEventArgs e) public void EditorGridKeyDown(object sender, KeyEventArgs e)
{ {
if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsDown) if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsDown)
Mouse.OverrideCursor = Cursors.ScrollAll; Cursor = Cursors.ScrollAll;
} }
public void EditorGridKeyUp(object sender, KeyEventArgs e) public void EditorGridKeyUp(object sender, KeyEventArgs e)
{ {
if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsUp) if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsUp)
Mouse.OverrideCursor = null; Cursor = null;
} }
public void Pan(object sender, MouseEventArgs e) public void Pan(object sender, MouseEventArgs e)

View File

@ -3,7 +3,10 @@ using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
using PropertyChanged;
using RGB.NET.Core;
using Stylet; using Stylet;
using Point = System.Windows.Point;
namespace Artemis.UI.Screens.SurfaceEditor.Visualization namespace Artemis.UI.Screens.SurfaceEditor.Visualization
{ {
@ -23,52 +26,44 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
foreach (var led in Device.RgbDevice) foreach (var led in Device.RgbDevice)
_leds.Add(new SurfaceLedViewModel(led)); _leds.Add(new SurfaceLedViewModel(led));
} }
Device.DeviceUpdated += DeviceOnDeviceUpdated;
}
private void DeviceOnDeviceUpdated(object sender, EventArgs e)
{
NotifyOfPropertyChange(() => RgbDeviceRectangle);
NotifyOfPropertyChange(() => Device.RgbDevice);
} }
public Device Device { get; set; } public Device Device { get; set; }
public SelectionStatus SelectionStatus { get; set; } public SelectionStatus SelectionStatus { get; set; }
public Cursor Cursor { get; set; } public Cursor Cursor { get; set; }
public double X public Rectangle RgbDeviceRectangle => Device.RgbDevice.DeviceRectangle;
{
get => Device.X;
set => Device.X = value;
}
public double Y
{
get => Device.Y;
set => Device.Y = value;
}
public int ZIndex
{
get => Device.ZIndex;
set => Device.ZIndex = value;
}
public IReadOnlyCollection<SurfaceLedViewModel> Leds => _leds.AsReadOnly(); public IReadOnlyCollection<SurfaceLedViewModel> Leds => _leds.AsReadOnly();
public Rect DeviceRectangle => Device.RgbDevice == null public Rect DeviceRectangle => Device.RgbDevice == null
? new Rect() ? new Rect()
: new Rect(X, Y, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height); : new Rect(Device.X, Device.Y, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height);
public void StartMouseDrag(Point mouseStartPosition) public void StartMouseDrag(Point mouseStartPosition)
{ {
_dragOffsetX = X - mouseStartPosition.X; _dragOffsetX = Device.X - mouseStartPosition.X;
_dragOffsetY = Y - mouseStartPosition.Y; _dragOffsetY = Device.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;
X = Math.Max(0, roundedX); Device.X = Math.Max(0, roundedX);
Y = Math.Max(0, roundedY); Device.Y = Math.Max(0, roundedY);
} }
// ReSharper disable once UnusedMember.Global - Called from view // ReSharper disable once UnusedMember.Global - Called from view
public void MouseEnter() public void MouseEnter(object sender, MouseEventArgs e)
{ {
if (SelectionStatus == SelectionStatus.None) if (SelectionStatus == SelectionStatus.None)
{ {
@ -86,6 +81,25 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
Cursor = Cursors.Arrow; Cursor = Cursors.Arrow;
} }
} }
public MouseDevicePosition GetMouseDevicePosition(Point position)
{
if ((new Point(0, 0) - position).LengthSquared < 5)
{
return MouseDevicePosition.TopLeft;
}
return MouseDevicePosition.Regular;
}
}
public enum MouseDevicePosition
{
Regular,
TopLeft,
TopRight,
BottomLeft,
BottomRight
} }
public enum SelectionStatus public enum SelectionStatus

View File

@ -1,4 +1,7 @@
using System.Threading.Tasks; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Artemis.UI.Screens.Dialogs; using Artemis.UI.Screens.Dialogs;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.ViewModels.Dialogs; using Artemis.UI.ViewModels.Dialogs;
@ -7,7 +10,7 @@ using Ninject;
using Ninject.Parameters; using Ninject.Parameters;
using Stylet; using Stylet;
namespace Artemis.UI.Services namespace Artemis.UI.Services.Dialog
{ {
public class DialogService : IDialogService public class DialogService : IDialogService
{ {
@ -46,16 +49,44 @@ namespace Artemis.UI.Services
return (bool) result; return (bool) result;
} }
public async Task<object> ShowDialog<T>(IParameter[] parameters = null) where T : DialogViewModelBase public async Task<object> ShowDialog<T>() where T : DialogViewModelBase
{ {
var viewModel = parameters != null ? _kernel.Get<T>(parameters) : _kernel.Get<T>(); return await ShowDialog("RootDialog", _kernel.Get<T>());
return await ShowDialog(null, viewModel);
} }
public async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters = null) where T : DialogViewModelBase public Task<object> ShowDialog<T>(Dictionary<string, object> parameters) where T : DialogViewModelBase
{ {
var viewModel = parameters != null ? _kernel.Get<T>(parameters) : _kernel.Get<T>(); if (parameters == null)
return await ShowDialog(identifier, viewModel); throw new ArgumentNullException(nameof(parameters));
var paramsArray = parameters.Select(kv => new ConstructorArgument(kv.Key, kv.Value)).Cast<IParameter>().ToArray();
return ShowDialog<T>(paramsArray);
}
public async Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
return await ShowDialog("RootDialog", _kernel.Get<T>(parameters));
}
public async Task<object> ShowDialogAt<T>(string identifier) where T : DialogViewModelBase
{
return await ShowDialog(identifier, _kernel.Get<T>());
}
public async Task<object> ShowDialogAt<T>(string identifier, Dictionary<string, object> parameters) where T : DialogViewModelBase
{
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
var paramsArray = parameters.Select(kv => new ConstructorArgument(kv.Key, kv.Value)).Cast<IParameter>().ToArray();
return await ShowDialogAt<T>(identifier, paramsArray);
}
public async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
return await ShowDialog(identifier, _kernel.Get<T>(parameters));
} }
private async Task<object> ShowDialog(string identifier, DialogViewModelBase viewModel) private async Task<object> ShowDialog(string identifier, DialogViewModelBase viewModel)

View File

@ -1,14 +1,97 @@
using System.Threading.Tasks; using System.Collections.Generic;
using System.Threading.Tasks;
using Artemis.UI.ViewModels.Dialogs; using Artemis.UI.ViewModels.Dialogs;
using MaterialDesignThemes.Wpf;
using Ninject.Parameters; using Ninject.Parameters;
namespace Artemis.UI.Services.Interfaces namespace Artemis.UI.Services.Interfaces
{ {
public interface IDialogService : IArtemisUIService public interface IDialogService : IArtemisUIService
{ {
/// <summary>
/// Shows a confirm dialog on the dialog host provided in <see cref="identifier" />.
/// </summary>
/// <param name="header">The title of the dialog</param>
/// <param name="text">The body text of the dialog</param>
/// <param name="confirmText">The text of the confirm button, defaults to "Confirm"</param>
/// <param name="cancelText">The text of the cancel button, defaults to "Cancel"</param>
/// <returns>A task that resolves to true if confirmed and false if cancelled</returns>
Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel"); Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel");
/// <summary>
/// Shows a confirm dialog on the dialog host provided in <see cref="identifier" />.
/// </summary>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="header">The title of the dialog</param>
/// <param name="text">The body text of the dialog</param>
/// <param name="confirmText">The text of the confirm button, defaults to "Confirm"</param>
/// <param name="cancelText">The text of the cancel button, defaults to "Cancel"</param>
/// <returns>A task that resolves to true if confirmed and false if cancelled</returns>
Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel"); Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel");
Task<object> ShowDialog<T>(IParameter[] parameters = null) where T : DialogViewModelBase;
Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters = null) where T : DialogViewModelBase; /// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" />
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>() where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> with arguments passed
/// to the view models constructor
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="parameters">A dictionary of constructor arguments to pass to the view model</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>(Dictionary<string, object> parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> using an array of
/// Ninject <see cref="IParameter" />, requires you to reference Ninject
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="parameters">An array of Ninject <see cref="IParameter" /> to pass to the view model during activation</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" />
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> with arguments passed
/// to the view models constructor
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="parameters">A dictionary of constructor arguments to pass to the view model</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier, Dictionary<string, object> parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> using an array of
/// Ninject <see cref="IParameter" />, requires you to reference Ninject
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="parameters">An array of Ninject <see cref="IParameter" /> to pass to the view model during activation</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase;
} }
} }