diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj
index b77c9e7fd..2080d665d 100644
--- a/src/Artemis.Core/Artemis.Core.csproj
+++ b/src/Artemis.Core/Artemis.Core.csproj
@@ -192,8 +192,9 @@
-
-
+
+
+
diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs
index f8a76cdf1..b7d871f5c 100644
--- a/src/Artemis.Core/Models/Profile/Profile.cs
+++ b/src/Artemis.Core/Models/Profile/Profile.cs
@@ -11,9 +11,21 @@ namespace Artemis.Core.Models.Profile
{
public class Profile : IProfileElement
{
- private Profile(PluginInfo pluginInfo)
+ internal Profile(PluginInfo pluginInfo, ProfileEntity profileEntity, IPluginService pluginService)
{
PluginInfo = pluginInfo;
+ Name = profileEntity.Name;
+
+ // Populate the profile starting at the root, the rest is populated recursively
+ Children = new List {Folder.FromFolderEntity(this, profileEntity.RootFolder, pluginService)};
+ }
+
+ internal Profile(PluginInfo pluginInfo, string name)
+ {
+ PluginInfo = pluginInfo;
+ Name = name;
+
+ Children = new List();
}
public PluginInfo PluginInfo { get; }
@@ -46,18 +58,6 @@ namespace Artemis.Core.Models.Profile
}
}
- public static Profile FromProfileEntity(PluginInfo pluginInfo, ProfileEntity profileEntity, IPluginService pluginService)
- {
- var profile = new Profile(pluginInfo) {Name = profileEntity.Name};
- lock (profile)
- {
- // Populate the profile starting at the root, the rest is populated recursively
- profile.Children.Add(Folder.FromFolderEntity(profile, profileEntity.RootFolder, pluginService));
-
- return profile;
- }
- }
-
public void Activate()
{
lock (this)
diff --git a/src/Artemis.Core/Plugins/Abstract/ModuleViewModel.cs b/src/Artemis.Core/Plugins/Abstract/ModuleViewModel.cs
index ead43c4e7..baacbe5bf 100644
--- a/src/Artemis.Core/Plugins/Abstract/ModuleViewModel.cs
+++ b/src/Artemis.Core/Plugins/Abstract/ModuleViewModel.cs
@@ -4,13 +4,12 @@ namespace Artemis.Core.Plugins.Abstract
{
public abstract class ModuleViewModel : Screen
{
- protected ModuleViewModel(Module module, string name)
+ protected ModuleViewModel(Module module, string displayName)
{
Module = module;
- Name = name;
+ DisplayName = displayName;
}
-
- public string Name { get; }
+
public Module Module { get; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
index 8e0a8992e..a72e7bb5d 100644
--- a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
+++ b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
@@ -46,6 +46,19 @@ namespace Artemis.Core.Plugins.Abstract
ActiveProfile = profile;
ActiveProfile.Activate();
}
+
+ OnActiveProfileChanged();
}
+
+ #region Events
+
+ public event EventHandler ActiveProfileChanged;
+
+ protected virtual void OnActiveProfileChanged()
+ {
+ ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index ec41cb386..2e1bdd5ac 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -5,6 +5,7 @@ using Artemis.Core.Exceptions;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Services.Interfaces;
using Artemis.Core.Services.Storage;
+using Artemis.Core.Services.Storage.Interfaces;
using RGB.NET.Core;
using Serilog;
using Color = System.Drawing.Color;
diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
new file mode 100644
index 000000000..65db1b113
--- /dev/null
+++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Artemis.Core.Models.Profile;
+using Artemis.Core.Plugins.Abstract;
+using Artemis.Core.Services.Interfaces;
+
+namespace Artemis.Core.Services.Storage.Interfaces
+{
+ public interface IProfileService : IArtemisService
+ {
+ Task> GetProfiles(ProfileModule module);
+ Task GetActiveProfile(ProfileModule module);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/ISurfaceService.cs b/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
similarity index 97%
rename from src/Artemis.Core/Services/Storage/ISurfaceService.cs
rename to src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
index 50cea7b92..440a228a4 100644
--- a/src/Artemis.Core/Services/Storage/ISurfaceService.cs
+++ b/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
@@ -4,7 +4,7 @@ using Artemis.Core.Events;
using Artemis.Core.Models.Surface;
using Artemis.Core.Services.Interfaces;
-namespace Artemis.Core.Services.Storage
+namespace Artemis.Core.Services.Storage.Interfaces
{
public interface ISurfaceService : IArtemisService
{
diff --git a/src/Artemis.Core/Services/StorageService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
similarity index 53%
rename from src/Artemis.Core/Services/StorageService.cs
rename to src/Artemis.Core/Services/Storage/ProfileService.cs
index fcb4891a2..89de07f78 100644
--- a/src/Artemis.Core/Services/StorageService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -1,36 +1,46 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Artemis.Core.Models.Profile;
-using Artemis.Core.Plugins.Models;
+using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Services.Interfaces;
+using Artemis.Core.Services.Storage.Interfaces;
using Artemis.Storage.Repositories;
-namespace Artemis.Core.Services
+namespace Artemis.Core.Services.Storage
{
///
/// Provides access to profile storage
///
- public class StorageService : IStorageService
+ public class ProfileService : IProfileService
{
private readonly IPluginService _pluginService;
private readonly ProfileRepository _profileRepository;
- internal StorageService(IPluginService pluginService)
+ internal ProfileService(IPluginService pluginService)
{
_pluginService = pluginService;
_profileRepository = new ProfileRepository();
}
- public async Task> GetModuleProfiles(PluginInfo pluginInfo)
+ public async Task> GetProfiles(ProfileModule module)
{
- var profileEntities = await _profileRepository.GetByPluginGuidAsync(pluginInfo.Guid);
+ var profileEntities = await _profileRepository.GetByPluginGuidAsync(module.PluginInfo.Guid);
var profiles = new List();
foreach (var profileEntity in profileEntities)
- profiles.Add(Profile.FromProfileEntity(pluginInfo, profileEntity, _pluginService));
+ profiles.Add(Profile.FromProfileEntity(module.PluginInfo, profileEntity, _pluginService));
return profiles;
}
+ public async Task GetActiveProfile(ProfileModule module)
+ {
+ var profileEntity = await _profileRepository.GetActiveProfileByPluginGuidAsync(module.PluginInfo.Guid);
+ if (profileEntity == null)
+ return null;
+
+ return Profile.FromProfileEntity(module.PluginInfo, profileEntity, _pluginService);
+ }
+
public async Task SaveProfile(Profile profile)
{
// Find a matching profile entity to update
@@ -40,9 +50,4 @@ namespace Artemis.Core.Services
await _profileRepository.SaveAsync();
}
}
-
- public interface IStorageService
- {
- Task> GetModuleProfiles(PluginInfo pluginInfo);
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs
index f57a7764e..9ab0d4c90 100644
--- a/src/Artemis.Core/Services/Storage/SurfaceService.cs
+++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs
@@ -8,6 +8,7 @@ using Artemis.Core.Extensions;
using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces;
+using Artemis.Core.Services.Storage.Interfaces;
using Artemis.Storage.Repositories.Interfaces;
using RGB.NET.Core;
using Serilog;
diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs
index 4547ccfef..54fd49f59 100644
--- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs
+++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs
@@ -11,7 +11,7 @@ using Device = Artemis.Core.Models.Surface.Device;
namespace Artemis.Plugins.Modules.General
{
- public class GeneralModule : Module
+ public class GeneralModule : ProfileModule
{
private readonly ColorBlend _rainbowColorBlend;
private readonly PluginSettings _settings;
diff --git a/src/Artemis.Storage/Entities/ProfileEntity.cs b/src/Artemis.Storage/Entities/ProfileEntity.cs
index 1e39e3b30..cfe8a98ec 100644
--- a/src/Artemis.Storage/Entities/ProfileEntity.cs
+++ b/src/Artemis.Storage/Entities/ProfileEntity.cs
@@ -11,6 +11,7 @@ namespace Artemis.Storage.Entities
public Guid PluginGuid { get; set; }
public string Name { get; set; }
+ public bool IsActive { get; set; }
public int RootFolderId { get; set; }
public virtual FolderEntity RootFolder { get; set; }
diff --git a/src/Artemis.Storage/Repositories/ProfileRepository.cs b/src/Artemis.Storage/Repositories/ProfileRepository.cs
index c4b0d544a..084cb236c 100644
--- a/src/Artemis.Storage/Repositories/ProfileRepository.cs
+++ b/src/Artemis.Storage/Repositories/ProfileRepository.cs
@@ -28,6 +28,11 @@ namespace Artemis.Storage.Repositories
return await _dbContext.Profiles.Where(p => p.PluginGuid == pluginGuid).ToListAsync();
}
+ public async Task GetActiveProfileByPluginGuidAsync(Guid pluginGuid)
+ {
+ return await _dbContext.Profiles.FirstOrDefaultAsync(p => p.PluginGuid == pluginGuid && p.IsActive);
+ }
+
public async Task GetByGuidAsync(string guid)
{
return await _dbContext.Profiles.FirstOrDefaultAsync(p => p.Guid == guid);
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index b1c65bcf8..ab4a6146f 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -181,6 +181,8 @@
+
+
@@ -245,6 +247,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/src/Artemis.UI/Ninject/Factories/IProfileEditorViewModelFactory.cs b/src/Artemis.UI/Ninject/Factories/IProfileEditorViewModelFactory.cs
index 6ed149c55..9875bea54 100644
--- a/src/Artemis.UI/Ninject/Factories/IProfileEditorViewModelFactory.cs
+++ b/src/Artemis.UI/Ninject/Factories/IProfileEditorViewModelFactory.cs
@@ -5,6 +5,6 @@ namespace Artemis.UI.Ninject.Factories
{
public interface IProfileEditorViewModelFactory
{
- ProfileEditorViewModel CreateModuleViewModel(Module module);
+ ProfileEditorViewModel CreateModuleViewModel(ProfileModule module);
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Ninject/UiModule.cs b/src/Artemis.UI/Ninject/UiModule.cs
index fe53db1a8..5d9869b46 100644
--- a/src/Artemis.UI/Ninject/UiModule.cs
+++ b/src/Artemis.UI/Ninject/UiModule.cs
@@ -1,5 +1,6 @@
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens;
+using Artemis.UI.Screens.Module.ProfileEditor;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Stylet;
using Artemis.UI.ViewModels.Dialogs;
@@ -38,6 +39,15 @@ namespace Artemis.UI.Ninject
Bind().ToFactory();
Bind().ToFactory();
+ // Bind profile editor VMs
+ Kernel.Bind(x =>
+ {
+ x.FromThisAssembly()
+ .SelectAllClasses()
+ .InheritedFrom()
+ .BindAllBaseClasses();
+ });
+
// Bind all UI services as singletons
Kernel.Bind(x =>
{
diff --git a/src/Artemis.UI/Screens/Module/ModuleRootView.xaml b/src/Artemis.UI/Screens/Module/ModuleRootView.xaml
index 0a0582796..842c06649 100644
--- a/src/Artemis.UI/Screens/Module/ModuleRootView.xaml
+++ b/src/Artemis.UI/Screens/Module/ModuleRootView.xaml
@@ -14,7 +14,7 @@
-
+
diff --git a/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs b/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
index a299832c5..9efa15d3d 100644
--- a/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
@@ -1,11 +1,12 @@
-using System.Threading.Tasks;
+using System.Linq;
+using System.Threading.Tasks;
using Artemis.Core.Plugins.Abstract;
using Artemis.UI.Ninject.Factories;
using Stylet;
namespace Artemis.UI.Screens.Module
{
- public class ModuleRootViewModel : Conductor.Collection.OneActive
+ public class ModuleRootViewModel : Conductor.Collection.OneActive
{
private readonly IProfileEditorViewModelFactory _profileEditorViewModelFactory;
@@ -27,14 +28,16 @@ namespace Artemis.UI.Screens.Module
await Task.Delay(400);
// Create the profile editor and module VMs
- var profileEditor = _profileEditorViewModelFactory.CreateModuleViewModel(Module);
+ if (Module is ProfileModule profileModule)
+ {
+ var profileEditor = _profileEditorViewModelFactory.CreateModuleViewModel(profileModule);
+ Items.Add(profileEditor);
+ }
+
var moduleViewModels = Module.GetViewModels();
-
- Items.Add(profileEditor);
Items.AddRange(moduleViewModels);
-
- // Activate the profile editor
- ActiveItem = profileEditor;
+
+ ActiveItem = Items.FirstOrDefault();
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
index 7bf9b1a8e..9f8ca9b7f 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{
- class DisplayConditionsViewModel
+ public class DisplayConditionsViewModel : ProfileEditorPanelViewModel
{
}
}
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ElementProperties/ElementPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ElementProperties/ElementPropertiesViewModel.cs
index 5f2db30a7..463f037b8 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/ElementProperties/ElementPropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ElementProperties/ElementPropertiesViewModel.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.ElementProperties
{
- class ElementPropertiesViewModel
+ public class ElementPropertiesViewModel : ProfileEditorPanelViewModel
{
}
}
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerElements/LayerElementsViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerElements/LayerElementsViewModel.cs
index 594150b1b..9200ff227 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerElements/LayerElementsViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerElements/LayerElementsViewModel.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerElements
{
- public class LayerElementsViewModel
+ public class LayerElementsViewModel : ProfileEditorPanelViewModel
{
}
}
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Layers/LayersViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Layers/LayersViewModel.cs
index 6efa9ec85..58c4de160 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/Layers/LayersViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Layers/LayersViewModel.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.Layers
{
- public class LayersViewModel
+ public class LayersViewModel : ProfileEditorPanelViewModel
{
}
}
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorPanelViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorPanelViewModel.cs
new file mode 100644
index 000000000..4d58d279f
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorPanelViewModel.cs
@@ -0,0 +1,8 @@
+using Stylet;
+
+namespace Artemis.UI.Screens.Module.ProfileEditor
+{
+ public class ProfileEditorPanelViewModel : Screen
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorView.xaml
index 21c6f6617..199b7e00e 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorView.xaml
@@ -17,31 +17,6 @@
-
-
@@ -58,129 +33,52 @@
-
+
The profile defines what colors the LEDs will have. Multiple groups of LEDs are defined into layers. On these layers you can apply effects.
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Initializing LED visualization...
-
-
-
-
-
+
@@ -194,13 +92,13 @@
- Right top
+
- Right bottom
+
@@ -214,13 +112,13 @@
- Bottom left
+
- Bottom right
+
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs
index 31000990c..5f5a49369 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs
@@ -1,220 +1,81 @@
using System;
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
using System.Linq;
-using System.Windows;
-using System.Windows.Input;
-using System.Windows.Media;
-using Artemis.Core.Events;
-using Artemis.Core.Models.Surface;
+using System.Threading.Tasks;
+using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.Abstract;
-using Artemis.Core.Services;
-using Artemis.Core.Services.Storage;
+using Artemis.Core.Services.Storage.Interfaces;
+using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions;
+using Artemis.UI.Screens.Module.ProfileEditor.ElementProperties;
+using Artemis.UI.Screens.Module.ProfileEditor.LayerElements;
+using Artemis.UI.Screens.Module.ProfileEditor.Layers;
using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
-using Artemis.UI.Screens.Shared;
-using Artemis.UI.Screens.SurfaceEditor;
-using RGB.NET.Core;
using Stylet;
-using Point = System.Windows.Point;
namespace Artemis.UI.Screens.Module.ProfileEditor
{
- public class ProfileEditorViewModel : ModuleViewModel
+ public class ProfileEditorViewModel : Conductor.Collection.AllActive
{
- private readonly TimerUpdateTrigger _updateTrigger;
+ private readonly IProfileService _profileService;
- public ProfileEditorViewModel(Core.Plugins.Abstract.Module module, ISurfaceService surfaceService, ISettingsService settingsService) : base(module, "Profile Editor")
+ public ProfileEditorViewModel(ProfileModule module, ICollection viewModels, IProfileService profileService)
{
- surfaceService.ActiveSurfaceConfigurationChanged += OnActiveSurfaceConfigurationChanged;
- Devices = new ObservableCollection();
- Execute.OnUIThread(() =>
- {
- SelectionRectangle = new RectangleGeometry();
- PanZoomViewModel = new PanZoomViewModel();
- });
+ _profileService = profileService;
- ApplySurfaceConfiguration(surfaceService.ActiveSurface);
+ DisplayName = "Profile editor";
+ Module = module;
- // Borrow RGB.NET's update trigger but limit the FPS
- var targetFpsSetting = settingsService.GetSetting("TargetFrameRate", 25);
- var editorTargetFpsSetting = settingsService.GetSetting("EditorTargetFrameRate", 15);
- var targetFps = Math.Min(targetFpsSetting.Value, editorTargetFpsSetting.Value);
- _updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / targetFps};
- _updateTrigger.Update += UpdateLeds;
+ DisplayConditionsViewModel = (DisplayConditionsViewModel) viewModels.First(vm => vm is DisplayConditionsViewModel);
+ ElementPropertiesViewModel = (ElementPropertiesViewModel) viewModels.First(vm => vm is ElementPropertiesViewModel);
+ LayerElementsViewModel = (LayerElementsViewModel) viewModels.First(vm => vm is LayerElementsViewModel);
+ LayersViewModel = (LayersViewModel) viewModels.First(vm => vm is LayersViewModel);
+ ProfileViewModel = (ProfileViewModel) viewModels.First(vm => vm is ProfileViewModel);
+
+ Items.AddRange(viewModels);
+
+ module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
}
- public ObservableCollection Devices { get; set; }
- public bool IsInitializing { get; private set; }
- public RectangleGeometry SelectionRectangle { get; set; }
- public PanZoomViewModel PanZoomViewModel { get; set; }
+ public Core.Plugins.Abstract.Module Module { get; }
+ public DisplayConditionsViewModel DisplayConditionsViewModel { get; }
+ public ElementPropertiesViewModel ElementPropertiesViewModel { get; }
+ public LayerElementsViewModel LayerElementsViewModel { get; }
+ public LayersViewModel LayersViewModel { get; }
+ public ProfileViewModel ProfileViewModel { get; }
- private void OnActiveSurfaceConfigurationChanged(object sender, SurfaceConfigurationEventArgs e)
+ public BindableCollection Profiles { get; set; }
+ public Profile SelectedProfile { get; set; }
+ public bool CanDeleteActiveProfile => SelectedProfile != null;
+
+ public async Task AddProfile()
{
- ApplySurfaceConfiguration(e.Surface);
}
- private void UpdateLeds(object sender, CustomUpdateData customUpdateData)
+ public async Task DeleteActiveProfile()
{
- if (IsInitializing)
- IsInitializing = Devices.Any(d => !d.AddedLeds);
-
- foreach (var profileDeviceViewModel in Devices)
- profileDeviceViewModel.Update();
}
- private void ApplySurfaceConfiguration(Surface surface)
+ private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
{
- // Make sure all devices have an up-to-date VM
- foreach (var surfaceDeviceConfiguration in surface.Devices)
- {
- // Create VMs for missing devices
- var viewModel = Devices.FirstOrDefault(vm => vm.Device.RgbDevice == surfaceDeviceConfiguration.RgbDevice);
- if (viewModel == null)
- {
- // Create outside the UI thread to avoid slowdowns as much as possible
- var profileDeviceViewModel = new ProfileDeviceViewModel(surfaceDeviceConfiguration);
- Execute.OnUIThread(() =>
- {
- // Gotta call IsInitializing on the UI thread or its never gets picked up
- IsInitializing = true;
- lock (Devices)
- {
- Devices.Add(profileDeviceViewModel);
- }
- });
- }
- // Update existing devices
- else
- viewModel.Device = surfaceDeviceConfiguration;
- }
-
- // Sort the devices by ZIndex
- Execute.OnUIThread(() =>
- {
- lock (Devices)
- {
- foreach (var device in Devices.OrderBy(d => d.ZIndex).ToList())
- Devices.Move(Devices.IndexOf(device), device.ZIndex - 1);
- }
- });
+ SelectedProfile = ((ProfileModule) Module).ActiveProfile;
}
protected override void OnActivate()
{
- _updateTrigger.Start();
+ Task.Run(LoadProfilesAsync);
base.OnActivate();
}
- protected override void OnDeactivate()
+ private async Task LoadProfilesAsync()
{
- _updateTrigger.Stop();
- base.OnDeactivate();
- }
+ var profiles = await _profileService.GetProfiles((ProfileModule) Module);
+ Profiles.Clear();
+ Profiles.AddRange(profiles);
- #region Selection
-
- private MouseDragStatus _mouseDragStatus;
- private Point _mouseDragStartPoint;
-
- // ReSharper disable once UnusedMember.Global - Called from view
- public void EditorGridMouseClick(object sender, MouseEventArgs e)
- {
- if (IsPanKeyDown())
- return;
-
- var position = e.GetPosition((IInputElement) sender);
- var relative = PanZoomViewModel.GetRelativeMousePosition(sender, e);
- if (e.LeftButton == MouseButtonState.Pressed)
- StartMouseDrag(position, relative);
- else
- StopMouseDrag(position);
- }
-
- // ReSharper disable once UnusedMember.Global - Called from view
- public void EditorGridMouseMove(object sender, MouseEventArgs e)
- {
- // If holding down Ctrl, pan instead of move/select
- if (IsPanKeyDown())
+ if (!profiles.Any())
{
- Pan(sender, e);
- return;
- }
-
- var position = e.GetPosition((IInputElement) sender);
- if (_mouseDragStatus == MouseDragStatus.Selecting)
- UpdateSelection(position);
- }
-
- private void StartMouseDrag(Point position, Point relative)
- {
- _mouseDragStatus = MouseDragStatus.Selecting;
- _mouseDragStartPoint = position;
-
- // Any time dragging starts, start with a new rect
- SelectionRectangle.Rect = new Rect();
- }
-
- private void StopMouseDrag(Point position)
- {
- var selectedRect = new Rect(_mouseDragStartPoint, position);
- // TODO: Select LEDs
-
- Mouse.OverrideCursor = null;
- _mouseDragStatus = MouseDragStatus.None;
- }
-
- private void UpdateSelection(Point position)
- {
- if (IsPanKeyDown())
- return;
-
- lock (Devices)
- {
- var selectedRect = new Rect(_mouseDragStartPoint, position);
- SelectionRectangle.Rect = selectedRect;
-
- // TODO: Highlight LEDs
+ var profile = new Profile();
}
}
-
- #endregion
-
- #region Panning and zooming
-
- public void EditorGridMouseWheel(object sender, MouseWheelEventArgs e)
- {
- PanZoomViewModel.ProcessMouseScroll(sender, e);
- }
-
- public void EditorGridKeyDown(object sender, KeyEventArgs e)
- {
- if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsDown)
- Mouse.OverrideCursor = Cursors.ScrollAll;
- }
-
- public void EditorGridKeyUp(object sender, KeyEventArgs e)
- {
- if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsUp)
- Mouse.OverrideCursor = null;
- }
-
- public void Pan(object sender, MouseEventArgs e)
- {
- PanZoomViewModel.ProcessMouseMove(sender, e);
-
- // Empty the selection rect since it's shown while mouse is down
- SelectionRectangle.Rect = Rect.Empty;
- }
-
- public void ResetZoomAndPan()
- {
- PanZoomViewModel.Reset();
- }
-
- private bool IsPanKeyDown()
- {
- return Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
- }
-
- #endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileView.xaml
new file mode 100644
index 000000000..9a62e9eda
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileView.xaml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Initializing LED visualization...
+
+
+
+
+
+
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs
new file mode 100644
index 000000000..24ddf9d50
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileViewModel.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using Artemis.Core.Events;
+using Artemis.Core.Models.Surface;
+using Artemis.Core.Services;
+using Artemis.Core.Services.Storage;
+using Artemis.Core.Services.Storage.Interfaces;
+using Artemis.UI.Screens.Shared;
+using Artemis.UI.Screens.SurfaceEditor;
+using RGB.NET.Core;
+using Stylet;
+using Point = System.Windows.Point;
+
+namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
+{
+ public class ProfileViewModel : ProfileEditorPanelViewModel
+ {
+ private readonly TimerUpdateTrigger _updateTrigger;
+
+ public ProfileViewModel(ISurfaceService surfaceService, ISettingsService settingsService)
+ {
+ Devices = new ObservableCollection();
+ Execute.OnUIThread(() =>
+ {
+ SelectionRectangle = new RectangleGeometry();
+ PanZoomViewModel = new PanZoomViewModel();
+ });
+
+ ApplySurfaceConfiguration(surfaceService.ActiveSurface);
+
+ // Borrow RGB.NET's update trigger but limit the FPS
+ var targetFpsSetting = settingsService.GetSetting("TargetFrameRate", 25);
+ var editorTargetFpsSetting = settingsService.GetSetting("EditorTargetFrameRate", 15);
+ var targetFps = Math.Min(targetFpsSetting.Value, editorTargetFpsSetting.Value);
+ _updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / targetFps};
+ _updateTrigger.Update += UpdateLeds;
+
+ surfaceService.ActiveSurfaceConfigurationChanged += OnActiveSurfaceConfigurationChanged;
+ }
+
+ public bool IsInitializing { get; private set; }
+ public ObservableCollection Devices { get; set; }
+ public RectangleGeometry SelectionRectangle { get; set; }
+ public PanZoomViewModel PanZoomViewModel { get; set; }
+
+ private void OnActiveSurfaceConfigurationChanged(object sender, SurfaceConfigurationEventArgs e)
+ {
+ ApplySurfaceConfiguration(e.Surface);
+ }
+
+ private void ApplySurfaceConfiguration(Surface surface)
+ {
+ // Make sure all devices have an up-to-date VM
+ foreach (var surfaceDeviceConfiguration in surface.Devices)
+ {
+ // Create VMs for missing devices
+ var viewModel = Devices.FirstOrDefault(vm => vm.Device.RgbDevice == surfaceDeviceConfiguration.RgbDevice);
+ if (viewModel == null)
+ {
+ // Create outside the UI thread to avoid slowdowns as much as possible
+ var profileDeviceViewModel = new ProfileDeviceViewModel(surfaceDeviceConfiguration);
+ Execute.OnUIThread(() =>
+ {
+ // Gotta call IsInitializing on the UI thread or its never gets picked up
+ IsInitializing = true;
+ lock (Devices)
+ {
+ Devices.Add(profileDeviceViewModel);
+ }
+ });
+ }
+ // Update existing devices
+ else
+ viewModel.Device = surfaceDeviceConfiguration;
+ }
+
+ // Sort the devices by ZIndex
+ Execute.OnUIThread(() =>
+ {
+ lock (Devices)
+ {
+ foreach (var device in Devices.OrderBy(d => d.ZIndex).ToList())
+ Devices.Move(Devices.IndexOf(device), device.ZIndex - 1);
+ }
+ });
+ }
+
+ private void UpdateLeds(object sender, CustomUpdateData customUpdateData)
+ {
+ if (IsInitializing)
+ IsInitializing = Devices.Any(d => !d.AddedLeds);
+
+ foreach (var profileDeviceViewModel in Devices)
+ profileDeviceViewModel.Update();
+ }
+
+ protected override void OnActivate()
+ {
+ _updateTrigger.Start();
+ base.OnActivate();
+ }
+
+ protected override void OnDeactivate()
+ {
+ _updateTrigger.Stop();
+ base.OnDeactivate();
+ }
+
+ #region Selection
+
+ private MouseDragStatus _mouseDragStatus;
+ private System.Windows.Point _mouseDragStartPoint;
+
+ // ReSharper disable once UnusedMember.Global - Called from view
+ public void EditorGridMouseClick(object sender, MouseEventArgs e)
+ {
+ if (IsPanKeyDown())
+ return;
+
+ var position = e.GetPosition((IInputElement)sender);
+ var relative = PanZoomViewModel.GetRelativeMousePosition(sender, e);
+ if (e.LeftButton == MouseButtonState.Pressed)
+ StartMouseDrag(position, relative);
+ else
+ StopMouseDrag(position);
+ }
+
+ // ReSharper disable once UnusedMember.Global - Called from view
+ public void EditorGridMouseMove(object sender, MouseEventArgs e)
+ {
+ // If holding down Ctrl, pan instead of move/select
+ if (IsPanKeyDown())
+ {
+ Pan(sender, e);
+ return;
+ }
+
+ var position = e.GetPosition((IInputElement)sender);
+ if (_mouseDragStatus == MouseDragStatus.Selecting)
+ UpdateSelection(position);
+ }
+
+ private void StartMouseDrag(System.Windows.Point position, System.Windows.Point relative)
+ {
+ _mouseDragStatus = MouseDragStatus.Selecting;
+ _mouseDragStartPoint = position;
+
+ // Any time dragging starts, start with a new rect
+ SelectionRectangle.Rect = new Rect();
+ }
+
+ private void StopMouseDrag(System.Windows.Point position)
+ {
+ var selectedRect = new Rect(_mouseDragStartPoint, position);
+ // TODO: Select LEDs
+
+ Mouse.OverrideCursor = null;
+ _mouseDragStatus = MouseDragStatus.None;
+ }
+
+ private void UpdateSelection(Point position)
+ {
+ if (IsPanKeyDown())
+ return;
+
+ lock (Devices)
+ {
+ var selectedRect = new Rect(_mouseDragStartPoint, position);
+ SelectionRectangle.Rect = selectedRect;
+
+ // TODO: Highlight LEDs
+ }
+ }
+
+ #endregion
+
+ #region Panning and zooming
+
+ public void EditorGridMouseWheel(object sender, MouseWheelEventArgs e)
+ {
+ PanZoomViewModel.ProcessMouseScroll(sender, e);
+ }
+
+ public void EditorGridKeyDown(object sender, KeyEventArgs e)
+ {
+ if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsDown)
+ Mouse.OverrideCursor = Cursors.ScrollAll;
+ }
+
+ public void EditorGridKeyUp(object sender, KeyEventArgs e)
+ {
+ if ((e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl) && e.IsUp)
+ Mouse.OverrideCursor = null;
+ }
+
+ public void Pan(object sender, MouseEventArgs e)
+ {
+ PanZoomViewModel.ProcessMouseMove(sender, e);
+
+ // Empty the selection rect since it's shown while mouse is down
+ SelectionRectangle.Rect = Rect.Empty;
+ }
+
+ public void ResetZoomAndPan()
+ {
+ PanZoomViewModel.Reset();
+ }
+
+ private bool IsPanKeyDown()
+ {
+ return Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
index cf19d95c0..3a73b9924 100644
--- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
@@ -1,6 +1,7 @@
using Artemis.Core.Services;
using Artemis.Core.Services.Interfaces;
using Artemis.Core.Services.Storage;
+using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Screens.Settings.Debug;
using Artemis.UI.Screens.Settings.Tabs.Devices;
using Ninject;
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
index f78736aa1..1931fc00e 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
@@ -9,6 +9,7 @@ using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services;
using Artemis.Core.Services.Storage;
+using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Screens.SurfaceEditor.Dialogs;
using Artemis.UI.Screens.SurfaceEditor.Visualization;