diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 3527006e4..e34ff68d3 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -184,6 +184,10 @@ + + ProfileLayerView.xaml + + EllipseToolView.xaml @@ -332,6 +336,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml new file mode 100644 index 000000000..951ee9dcf --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml.cs new file mode 100644 index 000000000..5ed8f1f0c --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.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 Artemis.UI.Screens.Module.ProfileEditor.Visualization +{ + /// + /// Interaction logic for ProfileLayerView.xaml + /// + public partial class ProfileLayerView : UserControl + { + public ProfileLayerView() + { + InitializeComponent(); + } + } +} diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs new file mode 100644 index 000000000..78430d528 --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; +using Artemis.UI.Extensions; +using RGB.NET.Core; + +namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization +{ + public class ProfileLayerViewModel : CanvasViewModel + { + public ProfileLayerViewModel(Layer layer) + { + Layer = layer; + + CreateLayerGeometry(); + Layer.RenderPropertiesUpdated += (sender, args) => CreateLayerGeometry(); + } + + public Layer Layer { get; } + + public Geometry LayerGeometry { get; set; } + + private void CreateLayerGeometry() + { + var layerGeometry = Geometry.Empty; + + foreach (var led in Layer.Leds) + { + Geometry geometry; + switch (led.RgbLed.Shape) + { + case Shape.Custom: + if (led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad) + geometry = CreateCustomGeometry(led, 2.0); + else + geometry = CreateCustomGeometry(led, 1.0); + break; + case Shape.Rectangle: + if (led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad) + geometry = CreateKeyCapGeometry(led); + else + geometry = CreateRectangleGeometry(led); + break; + case Shape.Circle: + geometry = CreateCircleGeometry(led); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + layerGeometry = Geometry.Combine(layerGeometry, geometry, GeometryCombineMode.Union, null, 5, ToleranceType.Absolute); + } + + LayerGeometry = layerGeometry; + LayerGeometry.Freeze(); + } + + private Geometry CreateRectangleGeometry(ArtemisLed led) + { + return new RectangleGeometry(led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1)); + } + + private Geometry CreateCircleGeometry(ArtemisLed led) + { + return new EllipseGeometry(led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1)); + } + + private Geometry CreateKeyCapGeometry(ArtemisLed led) + { + return new RectangleGeometry(led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1), 1.6, 1.6); + } + + private Geometry CreateCustomGeometry(ArtemisLed led, double deflateAmount) + { + try + { + var geometry = Geometry.Combine( + Geometry.Empty, + Geometry.Parse(led.RgbLed.ShapeData), + GeometryCombineMode.Union, + new TransformGroup + { + Children = new TransformCollection + { + new ScaleTransform(led.RgbLed.ActualSize.Width - deflateAmount, led.RgbLed.ActualSize.Height - deflateAmount), + new TranslateTransform(deflateAmount / 2, deflateAmount / 2) + } + } + ); + return geometry; + } + catch (Exception) + { + return CreateRectangleGeometry(led); + } + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs index 4d30e85e8..76c88f52e 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs @@ -42,14 +42,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization }); ApplySurfaceConfiguration(surfaceService.ActiveSurface); + ApplyActiveProfile(); CreateUpdateTrigger(); ActivateToolByIndex(0); + _profileEditorService.SelectedProfileChanged += OnSelectedProfileChanged; _profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged; - _profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementChanged; + _profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated; eventAggregator.Subscribe(this); } + public bool IsInitializing { get; private set; } public ObservableCollection CanvasViewModels { get; set; } public PanZoomViewModel PanZoomViewModel { get; set; } @@ -116,6 +119,31 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization ApplySurfaceConfiguration(e.Surface); } + private void ApplyActiveProfile() + { + Execute.PostToUIThread(() => + { + lock (CanvasViewModels) + { + var layerViewModels = CanvasViewModels.Where(vm => vm is ProfileLayerViewModel).Cast().ToList(); + var layers = _profileEditorService.SelectedProfile?.GetAllLayers() ?? new List(); + + + // Add new layers missing a VM + foreach (var layer in layers) + { + if (layerViewModels.All(vm => vm.Layer != layer)) + CanvasViewModels.Add(new ProfileLayerViewModel(layer)); + } + + // Remove layers that no longer exist + var toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer)); + foreach (var profileLayerViewModel in toRemove) + CanvasViewModels.Remove(profileLayerViewModel); + } + }); + } + private void ApplySurfaceConfiguration(ArtemisSurface surface) { var devices = new List(); @@ -324,12 +352,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization UpdateLedsDimStatus(); } + private void OnSelectedProfileChanged(object sender, EventArgs e) + { + ApplyActiveProfile(); + } + private void OnSelectedProfileElementChanged(object sender, EventArgs e) { UpdateLedsDimStatus(); CanApplyToLayer = _profileEditorService.SelectedProfileElement is Layer; } + private void OnSelectedProfileElementUpdated(object sender, EventArgs e) + { + ApplyActiveProfile(); + UpdateLedsDimStatus(); + CanApplyToLayer = _profileEditorService.SelectedProfileElement is Layer; + } + public void Handle(MainWindowFocusChangedEvent message) { if (PauseRenderingOnFocusLoss == null || ScreenState != ScreenState.Active)