mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Added a Material-styled scrollbar
Cleaned up reorder code Reorganised profile editor layout and added panel titles
This commit is contained in:
parent
b8fbb3fa24
commit
06f014a294
@ -15,7 +15,7 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public sealed class Layer : ProfileElement
|
||||
{
|
||||
internal Layer(Profile profile, ProfileElement parent, string name)
|
||||
public Layer(Profile profile, ProfileElement parent, string name)
|
||||
{
|
||||
LayerEntity = new LayerEntity();
|
||||
EntityId = Guid.NewGuid();
|
||||
|
||||
@ -26,8 +26,8 @@ namespace Artemis.Core.Services
|
||||
internal RgbService(ILogger logger, ISettingsService settingsService)
|
||||
{
|
||||
_logger = logger;
|
||||
_renderScaleSetting = settingsService.GetSetting("RenderScale", 1.0);
|
||||
_targetFrameRateSetting = settingsService.GetSetting("TargetFrameRate", 25);
|
||||
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 1.0);
|
||||
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 25);
|
||||
|
||||
Surface = RGBSurface.Instance;
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ namespace Artemis.Core.Services.Storage
|
||||
_rgbService = rgbService;
|
||||
_pluginService = pluginService;
|
||||
_surfaceConfigurations = new List<Surface>();
|
||||
_renderScaleSetting = settingsService.GetSetting("RenderScale", 1.0);
|
||||
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 1.0);
|
||||
|
||||
LoadFromRepository();
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Storage.Entities;
|
||||
|
||||
namespace Artemis.Storage.Repositories.Interfaces
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
|
||||
<!-- Include the Dragablz Material Design style -->
|
||||
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml" />
|
||||
|
||||
<ResourceDictionary Source="ResourceDictionaries/Scrollbar.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- MahApps Brushes -->
|
||||
|
||||
@ -153,6 +153,8 @@
|
||||
<Compile Include="Converters\InverseBooleanConverter.cs" />
|
||||
<Compile Include="Converters\NullToImageConverter.cs" />
|
||||
<Compile Include="Converters\NullToVisibilityConverter.cs" />
|
||||
<Compile Include="DebugTriggers\TriggerTracing.cs" />
|
||||
<Compile Include="Exceptions\ArtemisCoreException.cs" />
|
||||
<Compile Include="Extensions\RgbColorExtensions.cs" />
|
||||
<Compile Include="Extensions\RgbRectangleExtensions.cs" />
|
||||
<Compile Include="Ninject\Factories\IArtemisUIFactory.cs" />
|
||||
@ -176,14 +178,11 @@
|
||||
<Compile Include="Screens\Module\ProfileEditor\ElementProperties\ElementPropertyViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementsViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\FolderView.xaml.cs">
|
||||
<DependentUpon>FolderView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\FolderViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\LayerViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElement\FolderViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElement\LayerViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElementsViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileEditorPanelViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\Abstract\ProfileElementViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElement\ProfileElementViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileViewModel.cs" />
|
||||
<Compile Include="Screens\News\NewsViewModel.cs" />
|
||||
<Compile Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigViewModelValidator.cs" />
|
||||
@ -219,6 +218,10 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Screens\Settings\SettingsViewModel.cs" />
|
||||
<Page Include="ResourceDictionaries\Scrollbar.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Screens\Module\ProfileEditor\Dialogs\ProfileCreateView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
@ -251,11 +254,11 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Screens\Module\ProfileEditor\ProfileElements\FolderView.xaml">
|
||||
<Page Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElement\FolderView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Screens\Module\ProfileEditor\ProfileElements\LayerView.xaml">
|
||||
<Page Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElement\LayerView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Artemis.Core.Ninject;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Ninject;
|
||||
@ -7,6 +9,7 @@ using Artemis.UI.Screens;
|
||||
using Artemis.UI.Screens.Splash;
|
||||
using Artemis.UI.Stylet;
|
||||
using Ninject;
|
||||
using Serilog;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI
|
||||
@ -31,12 +34,33 @@ namespace Artemis.UI
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
// Start the Artemis core
|
||||
_core = Kernel.Get<ICoreService>();
|
||||
// When the core is done, hide the splash and show the main window
|
||||
_core.Initialized += (sender, args) => ShowMainWindow(windowManager, splashViewModel);
|
||||
// While the core is instantiated, start listening for events on the splash
|
||||
splashViewModel.ListenToEvents();
|
||||
try
|
||||
{
|
||||
// Start the Artemis core
|
||||
_core = Kernel.Get<ICoreService>();
|
||||
// When the core is done, hide the splash and show the main window
|
||||
_core.Initialized += (sender, args) => ShowMainWindow(windowManager, splashViewModel);
|
||||
// While the core is instantiated, start listening for events on the splash
|
||||
splashViewModel.ListenToEvents();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var logger = Kernel.Get<ILogger>();
|
||||
logger.Fatal(e, "Fatal exception during initialization, shutting down.");
|
||||
|
||||
// TODO: A proper exception viewer
|
||||
Execute.OnUIThread(() =>
|
||||
{
|
||||
windowManager.ShowMessageBox(e.Message + "\n\n Please refer the log file for more details.",
|
||||
"Fatal exception during initialization",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error
|
||||
);
|
||||
Environment.Exit(1);
|
||||
});
|
||||
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -59,5 +83,13 @@ namespace Artemis.UI
|
||||
kernel.Load<CoreModule>();
|
||||
base.ConfigureIoC(kernel);
|
||||
}
|
||||
|
||||
protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
var logger = Kernel.Get<ILogger>();
|
||||
logger.Fatal(e.Exception, "Fatal exception, shutting down.");
|
||||
|
||||
base.OnUnhandledException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
208
src/Artemis.UI/DebugTriggers/TriggerTracing.cs
Normal file
208
src/Artemis.UI/DebugTriggers/TriggerTracing.cs
Normal file
@ -0,0 +1,208 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
// Code from http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html
|
||||
// No license specified - this code is trimmed out from Release build anyway so it should be ok using it this way
|
||||
|
||||
// HOWTO: add the following attached property to any trigger and you will see when it is activated/deactivated in the output window
|
||||
// TriggerTracing.TriggerName="your debug name"
|
||||
// TriggerTracing.TraceEnabled="True"
|
||||
|
||||
// Example:
|
||||
// <Trigger my:TriggerTracing.TriggerName="BoldWhenMouseIsOver"
|
||||
// my:TriggerTracing.TraceEnabled="True"
|
||||
// Property="IsMouseOver"
|
||||
// Value="True">
|
||||
// <Setter Property = "FontWeight" Value="Bold"/>
|
||||
// </Trigger>
|
||||
//
|
||||
// As this works on anything that inherits from TriggerBase, it will also work on <MultiTrigger>.
|
||||
|
||||
namespace Artemis.UI.DebugTriggers
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
/// <summary>
|
||||
/// Contains attached properties to activate Trigger Tracing on the specified Triggers.
|
||||
/// This file alone should be dropped into your app.
|
||||
/// </summary>
|
||||
public static class TriggerTracing
|
||||
{
|
||||
static TriggerTracing()
|
||||
{
|
||||
// Initialise WPF Animation tracing and add a TriggerTraceListener
|
||||
PresentationTraceSources.Refresh();
|
||||
PresentationTraceSources.AnimationSource.Listeners.Clear();
|
||||
PresentationTraceSources.AnimationSource.Listeners.Add(new TriggerTraceListener());
|
||||
PresentationTraceSources.AnimationSource.Switch.Level = SourceLevels.All;
|
||||
}
|
||||
|
||||
private enum TriggerTraceStoryboardType
|
||||
{
|
||||
Enter,
|
||||
Exit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dummy storyboard for tracing purposes
|
||||
/// </summary>
|
||||
private class TriggerTraceStoryboard : Storyboard
|
||||
{
|
||||
public TriggerTraceStoryboard(TriggerBase triggerBase, TriggerTraceStoryboardType storyboardType)
|
||||
{
|
||||
TriggerBase = triggerBase;
|
||||
StoryboardType = storyboardType;
|
||||
}
|
||||
|
||||
public TriggerTraceStoryboardType StoryboardType { get; }
|
||||
public TriggerBase TriggerBase { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom tracelistener.
|
||||
/// </summary>
|
||||
private class TriggerTraceListener : TraceListener
|
||||
{
|
||||
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
|
||||
{
|
||||
base.TraceEvent(eventCache, source, eventType, id, format, args);
|
||||
|
||||
if (format.StartsWith("Storyboard has begun;"))
|
||||
{
|
||||
var storyboard = args[1] as TriggerTraceStoryboard;
|
||||
if (storyboard != null)
|
||||
{
|
||||
// add a breakpoint here to see when your trigger has been
|
||||
// entered or exited
|
||||
|
||||
// the element being acted upon
|
||||
var targetElement = args[5];
|
||||
|
||||
// the namescope of the element being acted upon
|
||||
var namescope = (INameScope) args[7];
|
||||
|
||||
var triggerBase = storyboard.TriggerBase;
|
||||
var triggerName = GetTriggerName(storyboard.TriggerBase);
|
||||
|
||||
Debug.WriteLine("Element: {0}, {1}: {2}: {3}", targetElement, triggerBase.GetType().Name, triggerName, storyboard.StoryboardType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(string message)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteLine(string message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#region TriggerName attached property
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trigger name for the specified trigger. This will be used
|
||||
/// to identify the trigger in the debug output.
|
||||
/// </summary>
|
||||
/// <param name="trigger">The trigger.</param>
|
||||
/// <returns></returns>
|
||||
public static string GetTriggerName(TriggerBase trigger)
|
||||
{
|
||||
return (string) trigger.GetValue(TriggerNameProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the trigger name for the specified trigger. This will be used
|
||||
/// to identify the trigger in the debug output.
|
||||
/// </summary>
|
||||
/// <param name="trigger">The trigger.</param>
|
||||
/// <returns></returns>
|
||||
public static void SetTriggerName(TriggerBase trigger, string value)
|
||||
{
|
||||
trigger.SetValue(TriggerNameProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TriggerNameProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"TriggerName",
|
||||
typeof(string),
|
||||
typeof(TriggerTracing),
|
||||
new UIPropertyMetadata(string.Empty));
|
||||
|
||||
#endregion
|
||||
|
||||
#region TraceEnabled attached property
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indication whether trace is enabled for the specified trigger.
|
||||
/// </summary>
|
||||
/// <param name="trigger">The trigger.</param>
|
||||
/// <returns></returns>
|
||||
public static bool GetTraceEnabled(TriggerBase trigger)
|
||||
{
|
||||
return (bool) trigger.GetValue(TraceEnabledProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value specifying whether trace is enabled for the specified trigger
|
||||
/// </summary>
|
||||
/// <param name="trigger"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetTraceEnabled(TriggerBase trigger, bool value)
|
||||
{
|
||||
trigger.SetValue(TraceEnabledProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TraceEnabledProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"TraceEnabled",
|
||||
typeof(bool),
|
||||
typeof(TriggerTracing),
|
||||
new UIPropertyMetadata(false, OnTraceEnabledChanged));
|
||||
|
||||
private static void OnTraceEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var triggerBase = d as TriggerBase;
|
||||
|
||||
if (triggerBase == null)
|
||||
return;
|
||||
|
||||
if (!(e.NewValue is bool))
|
||||
return;
|
||||
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
// insert dummy story-boards which can later be traced using WPF animation tracing
|
||||
|
||||
var storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Enter);
|
||||
triggerBase.EnterActions.Insert(0, new BeginStoryboard {Storyboard = storyboard});
|
||||
|
||||
storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Exit);
|
||||
triggerBase.ExitActions.Insert(0, new BeginStoryboard {Storyboard = storyboard});
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove the dummy storyboards
|
||||
|
||||
foreach (var actionCollection in new[] {triggerBase.EnterActions, triggerBase.ExitActions})
|
||||
{
|
||||
foreach (var triggerAction in actionCollection)
|
||||
{
|
||||
var bsb = triggerAction as BeginStoryboard;
|
||||
|
||||
if (bsb != null && bsb.Storyboard != null && bsb.Storyboard is TriggerTraceStoryboard)
|
||||
{
|
||||
actionCollection.Remove(bsb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
}
|
||||
20
src/Artemis.UI/Exceptions/ArtemisCoreException.cs
Normal file
20
src/Artemis.UI/Exceptions/ArtemisCoreException.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.UI.Exceptions
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class ArtemisUIException : Exception
|
||||
{
|
||||
public ArtemisUIException()
|
||||
{
|
||||
}
|
||||
|
||||
public ArtemisUIException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ArtemisUIException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/Artemis.UI/ResourceDictionaries/Scrollbar.xaml
Normal file
142
src/Artemis.UI/ResourceDictionaries/Scrollbar.xaml
Normal file
@ -0,0 +1,142 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="StandardBorderBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="StandardBackgroundBrush" Color="#FFF" />
|
||||
<SolidColorBrush x:Key="HoverBorderBrush" Color="#DDD" />
|
||||
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
|
||||
<SolidColorBrush x:Key="SelectedForegroundBrush" Color="White" />
|
||||
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="NormalBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="NormalBorderBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="HorizontalNormalBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="HorizontalNormalBorderBrush" Color="#888" />
|
||||
<LinearGradientBrush x:Key="ListBoxBackgroundBrush" StartPoint="0,0" EndPoint="1,0.001">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="White" Offset="0.0" />
|
||||
<GradientStop Color="White" Offset="0.6" />
|
||||
<GradientStop Color="#DDDDDD" Offset="1.2" />
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
<LinearGradientBrush x:Key="StandardBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0" />
|
||||
<GradientStop Color="#CCC" Offset="1.0" />
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
|
||||
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#BBB" Offset="0.0" />
|
||||
<GradientStop Color="#EEE" Offset="0.1" />
|
||||
<GradientStop Color="#EEE" Offset="0.9" />
|
||||
<GradientStop Color="#FFF" Offset="1.0" />
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
<Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Setter Property="IsTabStop" Value="false" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Border Background="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Setter Property="IsTabStop" Value="false" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Border CornerRadius="2" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Track Name="PART_Track" IsDirectionReversed="true">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageUpCommand" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Style="{StaticResource ScrollBarThumb}" Margin="1" Background="{StaticResource HorizontalNormalBrush}" BorderBrush="{StaticResource HorizontalNormalBorderBrush}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageDownCommand" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Track Name="PART_Track" Grid.Column="1" IsDirectionReversed="False">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageLeftCommand" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Style="{StaticResource ScrollBarThumb}" Margin="1" Background="{StaticResource NormalBrush}" BorderBrush="{StaticResource NormalBorderBrush}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageRightCommand" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Orientation" Value="Horizontal">
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="Height" Value="10" />
|
||||
<Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Orientation" Value="Vertical">
|
||||
<Setter Property="Width" Value="10" />
|
||||
<Setter Property="Height" Value="Auto" />
|
||||
<Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="{x:Type ScrollViewer}" TargetType="{x:Type ScrollViewer}">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollContentPresenter Grid.ColumnSpan="2" Grid.RowSpan="2" />
|
||||
<ScrollBar Grid.Column="1" Name="PART_VerticalScrollBar" Value="{TemplateBinding VerticalOffset}" Maximum="{TemplateBinding ScrollableHeight}"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
|
||||
<ScrollBar Grid.Row="1" Name="PART_HorizontalScrollBar" Orientation="Horizontal" Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@ -6,5 +6,12 @@
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid />
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubheadingTextBlock}" Margin="10 5 0 -4">
|
||||
Display conditions
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -6,5 +6,12 @@
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ElementProperties"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid />
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubheadingTextBlock}" Margin="10 5 0 -4">
|
||||
Layer element properties
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -6,5 +6,12 @@
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerElements"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid />
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubheadingTextBlock}" Margin="10 5 0 -4">
|
||||
Layer elements
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -8,7 +8,7 @@
|
||||
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileEditorViewModel}}">
|
||||
d:DataContext="{x:Type profileEditor:ProfileEditorViewModel}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
@ -22,64 +22,113 @@
|
||||
|
||||
<Grid Margin="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" MinWidth="100" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="{Binding ProfileElementsWidth.Value, Mode=TwoWay}" MinWidth="100" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" MinHeight="100" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="200" />
|
||||
<RowDefinition Height="{Binding LayerElementsHeight.Value, Mode=TwoWay}" MinHeight="100" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
|
||||
<TextBlock>
|
||||
<materialDesign:PackIcon Kind="AboutOutline" Margin="0 0 0 -3" /> The profile defines what colors the LEDs will have. Multiple groups of LEDs are defined into layers. On these layers you can apply effects.
|
||||
</TextBlock>
|
||||
<Border BorderBrush="{DynamicResource MaterialDesignDivider}" BorderThickness="0 0 0 1" Margin="0 9 0 8" />
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="0" Grid.Column="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox Name="LocaleCombo"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
ItemsSource="{Binding Profiles}"
|
||||
SelectedItem="{Binding SelectedProfile}"
|
||||
DisplayMemberPath="Name">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
</ComboBox>
|
||||
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||
Margin="10 0"
|
||||
Grid.Column="1"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action AddProfile}">
|
||||
<materialDesign:PackIcon Kind="Add" Height="14" Width="14" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
|
||||
Grid.Column="2"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action DeleteActiveProfile}">
|
||||
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" />
|
||||
</Button>
|
||||
<!-- Left side -->
|
||||
<Grid Grid.Row="0" Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<!-- Introduction -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- Design area -->
|
||||
<RowDefinition Height="*" MinHeight="200"/>
|
||||
<!-- Bottom panels resize -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- Bottom panels -->
|
||||
<RowDefinition Height="{Binding BottomPanelsHeight.Value, Mode=TwoWay}" MinHeight="100"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Introduction -->
|
||||
<StackPanel Grid.Row="0" Margin="0 0 15 0">
|
||||
<TextBlock>
|
||||
<materialDesign:PackIcon Kind="AboutOutline" Margin="0 0 0 -4" /> The profile defines what colors the LEDs will have. Multiple groups of LEDs are defined into layers. On these layers you can apply effects.
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Design area -->
|
||||
<materialDesign:Card Grid.Row="1" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ProfileViewModel}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- Bottom panels resize -->
|
||||
<GridSplitter Grid.Row="2" Grid.Column="0" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
|
||||
<!-- Bottom panels -->
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MinWidth="100" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="{Binding ElementPropertiesWidth.Value, Mode=TwoWay}" MinWidth="100" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Layer elements -->
|
||||
<materialDesign:Card Grid.Column="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding LayerElementsViewModel}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- Element properties resize -->
|
||||
<GridSplitter Grid.Column="1" Width="5" Margin="5 0" HorizontalAlignment="Stretch" Cursor="SizeWE" />
|
||||
|
||||
<!-- Element properties -->
|
||||
<materialDesign:Card Grid.Column="2" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ElementPropertiesViewModel}" />
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Right panels resize -->
|
||||
<GridSplitter Grid.Row="0" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Cursor="SizeWE" Margin="5 0" />
|
||||
|
||||
<!-- Right side -->
|
||||
<Grid Grid.Row="0" Grid.Column="2">
|
||||
<!-- Profile selection -->
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox Name="LocaleCombo"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
ItemsSource="{Binding Profiles}"
|
||||
SelectedItem="{Binding SelectedProfile}"
|
||||
DisplayMemberPath="Name">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
</ComboBox>
|
||||
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||
Margin="10 0"
|
||||
Grid.Column="1"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action AddProfile}">
|
||||
<materialDesign:PackIcon Kind="Add" Height="14" Width="14" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
|
||||
Grid.Column="2"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action DeleteActiveProfile}">
|
||||
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- Design area -->
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ProfileViewModel}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<GridSplitter Grid.Row="1" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Cursor="SizeWE" Margin="5 0" />
|
||||
|
||||
@ -88,7 +137,7 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="{Binding DisplayConditionsHeight.Value, Mode=TwoWay}" MinHeight="100" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<materialDesign:Card Grid.Row="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
@ -102,24 +151,8 @@
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
<GridSplitter Grid.Row="2" Grid.Column="0" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
|
||||
<!-- Bottom panels -->
|
||||
<Grid Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:Card Grid.Column="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding LayerElementsViewModel}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<GridSplitter Grid.Column="1" Width="5" Margin="5 0" HorizontalAlignment="Stretch" Cursor="SizeWE" />
|
||||
|
||||
<materialDesign:Card Grid.Column="2" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ElementPropertiesViewModel}" />
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -2,8 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions;
|
||||
@ -19,10 +22,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
public class ProfileEditorViewModel : Conductor<ProfileEditorPanelViewModel>.Collection.AllActive
|
||||
{
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public ProfileEditorViewModel(ProfileModule module, ICollection<ProfileEditorPanelViewModel> viewModels, IProfileService profileService, IDialogService dialogService)
|
||||
public ProfileEditorViewModel(ProfileModule module, ICollection<ProfileEditorPanelViewModel> viewModels, IProfileService profileService,
|
||||
IDialogService dialogService, ISettingsService settingsService)
|
||||
{
|
||||
_profileService = profileService;
|
||||
_settingsService = settingsService;
|
||||
|
||||
DisplayName = "Profile editor";
|
||||
Module = module;
|
||||
@ -47,9 +53,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
public LayerElementsViewModel LayerElementsViewModel { get; }
|
||||
public ProfileElementsViewModel ProfileElementsViewModel { get; }
|
||||
public ProfileViewModel ProfileViewModel { get; }
|
||||
|
||||
public BindableCollection<Profile> Profiles { get; set; }
|
||||
|
||||
public PluginSetting<GridLength> ProfileElementsWidth { get; set; }
|
||||
public PluginSetting<GridLength> DisplayConditionsHeight { get; set; }
|
||||
public PluginSetting<GridLength> LayerElementsHeight { get; set; }
|
||||
public PluginSetting<GridLength> ElementPropertiesWidth { get; set; }
|
||||
|
||||
public Profile SelectedProfile
|
||||
{
|
||||
get => Module.ActiveProfile;
|
||||
@ -126,6 +136,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
LoadWorkspaceSettings();
|
||||
Task.Run(() =>
|
||||
{
|
||||
LoadProfiles();
|
||||
@ -138,6 +149,28 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
SaveWorkspaceSettings();
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private void LoadWorkspaceSettings()
|
||||
{
|
||||
ProfileElementsWidth = _settingsService.GetSetting("ProfileEditor.ProfileElementsWidth", new GridLength(550));
|
||||
DisplayConditionsHeight = _settingsService.GetSetting("ProfileEditor.DisplayConditionsHeight", new GridLength(320));
|
||||
LayerElementsHeight = _settingsService.GetSetting("ProfileEditor.LayerElementsHeight", new GridLength(350));
|
||||
ElementPropertiesWidth = _settingsService.GetSetting("ProfileEditor.ElementPropertiesWidth", new GridLength(920));
|
||||
}
|
||||
|
||||
private void SaveWorkspaceSettings()
|
||||
{
|
||||
ProfileElementsWidth.Save();
|
||||
DisplayConditionsHeight.Save();
|
||||
LayerElementsHeight.Save();
|
||||
ElementPropertiesWidth.Save();
|
||||
}
|
||||
|
||||
private void LoadProfiles()
|
||||
{
|
||||
// Get all profiles from the database
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Models.Profile.Abstract;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract
|
||||
{
|
||||
public abstract class ProfileElementViewModel : PropertyChangedBase
|
||||
{
|
||||
protected ProfileElementViewModel(FolderViewModel parent, ProfileElement profileElement, ProfileEditorViewModel profileEditorViewModel)
|
||||
{
|
||||
Parent = parent;
|
||||
ProfileElement = profileElement;
|
||||
ProfileEditorViewModel = profileEditorViewModel;
|
||||
|
||||
Children = new BindableCollection<ProfileElementViewModel>();
|
||||
}
|
||||
|
||||
public FolderViewModel Parent { get; set; }
|
||||
public ProfileEditorViewModel ProfileEditorViewModel { get; set; }
|
||||
|
||||
public ProfileElement ProfileElement { get; set; }
|
||||
public BindableCollection<ProfileElementViewModel> Children { get; set; }
|
||||
|
||||
public virtual void UpdateProfileElements()
|
||||
{
|
||||
// Order the children
|
||||
var vmsList = Children.OrderBy(v => v.ProfileElement.Order).ToList();
|
||||
for (var index = 0; index < vmsList.Count; index++)
|
||||
{
|
||||
var profileElementViewModel = vmsList[index];
|
||||
Children.Move(Children.IndexOf(profileElementViewModel), index);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetElementInFront(ProfileElementViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.Folder.RemoveChild(source.ProfileElement);
|
||||
Parent.Folder.AddChild(source.ProfileElement, ProfileElement.Order);
|
||||
Parent.UpdateProfileElements();
|
||||
}
|
||||
|
||||
public void SetElementBehind(ProfileElementViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.Folder.RemoveChild(source.ProfileElement);
|
||||
Parent.Folder.AddChild(source.ProfileElement, ProfileElement.Order + 1);
|
||||
Parent.UpdateProfileElements();
|
||||
}
|
||||
|
||||
public async Task RenameElement()
|
||||
{
|
||||
var result = await ProfileEditorViewModel.DialogService.ShowDialog<ProfileElementRenameViewModel>(
|
||||
new Dictionary<string, object> {{"profileElement", ProfileElement}}
|
||||
);
|
||||
if (result is string newName)
|
||||
{
|
||||
ProfileElement.Name = newName;
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteElement()
|
||||
{
|
||||
var result = await ProfileEditorViewModel.DialogService.ShowConfirmDialog(
|
||||
"Delete profile element",
|
||||
"Are you sure you want to delete this element? This cannot be undone."
|
||||
);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
// Farewell, cruel world
|
||||
var parent = Parent;
|
||||
ProfileElement.Parent.RemoveChild(ProfileElement);
|
||||
parent.RemoveExistingElement(this);
|
||||
parent.UpdateProfileElements();
|
||||
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for FolderView.xaml
|
||||
/// </summary>
|
||||
public partial class FolderView : UserControl
|
||||
{
|
||||
public FolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
{
|
||||
public class FolderViewModel : ProfileElementViewModel
|
||||
{
|
||||
public FolderViewModel(FolderViewModel parent, Folder folder, ProfileEditorViewModel profileEditorViewModel) : base(parent, folder, profileEditorViewModel)
|
||||
{
|
||||
Folder = folder;
|
||||
UpdateProfileElements();
|
||||
}
|
||||
|
||||
public Folder Folder { get; }
|
||||
|
||||
public void AddFolder()
|
||||
{
|
||||
Folder.AddFolder("New folder");
|
||||
UpdateProfileElements();
|
||||
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
public void AddLayer()
|
||||
{
|
||||
Folder.AddLayer("New layer");
|
||||
UpdateProfileElements();
|
||||
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
public void RemoveExistingElement(ProfileElementViewModel element)
|
||||
{
|
||||
Folder.RemoveChild(element.ProfileElement);
|
||||
Children.Remove(element);
|
||||
element.Parent = null;
|
||||
}
|
||||
|
||||
public void AddExistingElement(ProfileElementViewModel element)
|
||||
{
|
||||
Folder.AddChild(element.ProfileElement);
|
||||
Children.Add(element);
|
||||
element.Parent = this;
|
||||
}
|
||||
|
||||
public sealed override void UpdateProfileElements()
|
||||
{
|
||||
// Ensure every child element has an up-to-date VM
|
||||
if (Folder.Children != null)
|
||||
{
|
||||
foreach (var profileElement in Folder.Children.OrderBy(c => c.Order))
|
||||
{
|
||||
ProfileElementViewModel existing = null;
|
||||
if (profileElement is Folder folder)
|
||||
{
|
||||
existing = Children.FirstOrDefault(p => p is FolderViewModel vm && vm.Folder == folder);
|
||||
if (existing == null)
|
||||
Children.Add(new FolderViewModel(this, folder, ProfileEditorViewModel));
|
||||
}
|
||||
else if (profileElement is Layer layer)
|
||||
{
|
||||
existing = Children.FirstOrDefault(p => p is LayerViewModel vm && vm.Layer == layer);
|
||||
if (existing == null)
|
||||
Children.Add(new LayerViewModel(this, layer, ProfileEditorViewModel));
|
||||
}
|
||||
|
||||
existing?.UpdateProfileElements();
|
||||
}
|
||||
}
|
||||
|
||||
base.UpdateProfileElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
{
|
||||
public class LayerViewModel : ProfileElementViewModel
|
||||
{
|
||||
public LayerViewModel(FolderViewModel parent, Layer layer, ProfileEditorViewModel profileEditorViewModel) : base(parent, layer, profileEditorViewModel)
|
||||
{
|
||||
Layer = layer;
|
||||
}
|
||||
|
||||
public Layer Layer { get; }
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.FolderView"
|
||||
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement.FolderView"
|
||||
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"
|
||||
@ -6,10 +6,11 @@
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:profileElement="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:FolderViewModel}}">
|
||||
<!-- Margin is a bit hacky but the tree view puts a margin on 10 on us which when clicked outside of doesn't trigger the context menu -->
|
||||
d:DataContext="{d:DesignInstance {x:Type profileElement:FolderViewModel}}">
|
||||
<!-- Capture clicks on full tree view item -->
|
||||
<StackPanel Margin="-10" Background="Transparent">
|
||||
<StackPanel.ContextMenu>
|
||||
<ContextMenu>
|
||||
@ -37,8 +38,10 @@
|
||||
</ContextMenu>
|
||||
</StackPanel.ContextMenu>
|
||||
<StackPanel Orientation="Horizontal" Margin="10">
|
||||
<materialDesign:PackIcon Kind="Folder" />
|
||||
<TextBlock Text="{Binding Folder.Name}" Margin="10 0 0 0" />
|
||||
<materialDesign:PackIcon Kind="Folder" Visibility="{Binding IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}"/>
|
||||
<materialDesign:PackIcon Kind="FolderOpen" Visibility="{Binding IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}"/>
|
||||
|
||||
<TextBlock Text="{Binding ProfileElement.Name}" Margin="10 0 0 0" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement
|
||||
{
|
||||
public class FolderViewModel : ProfileElementViewModel
|
||||
{
|
||||
public FolderViewModel(ProfileElementViewModel parent, Core.Models.Profile.Abstract.ProfileElement folder, ProfileEditorViewModel profileEditorViewModel)
|
||||
: base(parent, folder, profileEditorViewModel)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool SupportsChildren => true;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.LayerView"
|
||||
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement.LayerView"
|
||||
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"
|
||||
@ -6,9 +6,11 @@
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:profileElement="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:LayerViewModel}}">
|
||||
d:DataContext="{d:DesignInstance {x:Type profileElement:LayerViewModel}}">
|
||||
<!-- Capture clicks on full tree view item -->
|
||||
<StackPanel Margin="-10" Background="Transparent">
|
||||
<StackPanel.ContextMenu>
|
||||
<ContextMenu>
|
||||
@ -26,7 +28,7 @@
|
||||
</StackPanel.ContextMenu>
|
||||
<StackPanel Orientation="Horizontal" Margin="10">
|
||||
<materialDesign:PackIcon Kind="Layers" />
|
||||
<TextBlock Text="{Binding Layer.Name}" Margin="10 0 0 0" />
|
||||
<TextBlock Text="{Binding ProfileElement.Name}" Margin="10 0 0 0" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement
|
||||
{
|
||||
public class LayerViewModel : ProfileElementViewModel
|
||||
{
|
||||
public LayerViewModel(ProfileElementViewModel parent, Core.Models.Profile.Abstract.ProfileElement layer, ProfileEditorViewModel profileEditorViewModel)
|
||||
: base(parent, layer, profileEditorViewModel)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool SupportsChildren => false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,163 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement
|
||||
{
|
||||
public abstract class ProfileElementViewModel : PropertyChangedBase
|
||||
{
|
||||
protected ProfileElementViewModel(ProfileElementViewModel parent, Core.Models.Profile.Abstract.ProfileElement profileElement, ProfileEditorViewModel profileEditorViewModel)
|
||||
{
|
||||
Parent = parent;
|
||||
ProfileElement = profileElement;
|
||||
ProfileEditorViewModel = profileEditorViewModel;
|
||||
|
||||
Children = new BindableCollection<ProfileElementViewModel>();
|
||||
UpdateProfileElements();
|
||||
}
|
||||
|
||||
public abstract bool SupportsChildren { get; }
|
||||
public ProfileElementViewModel Parent { get; set; }
|
||||
public ProfileEditorViewModel ProfileEditorViewModel { get; set; }
|
||||
|
||||
public Core.Models.Profile.Abstract.ProfileElement ProfileElement { get; set; }
|
||||
public BindableCollection<ProfileElementViewModel> Children { get; set; }
|
||||
|
||||
public void SetElementInFront(ProfileElementViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.ProfileElement.RemoveChild(source.ProfileElement);
|
||||
Parent.ProfileElement.AddChild(source.ProfileElement, ProfileElement.Order);
|
||||
Parent.UpdateProfileElements();
|
||||
}
|
||||
|
||||
public void SetElementBehind(ProfileElementViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.ProfileElement.RemoveChild(source.ProfileElement);
|
||||
Parent.ProfileElement.AddChild(source.ProfileElement, ProfileElement.Order + 1);
|
||||
Parent.UpdateProfileElements();
|
||||
}
|
||||
|
||||
public void RemoveExistingElement(ProfileElementViewModel element)
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot remove a child from a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.RemoveChild(element.ProfileElement);
|
||||
Children.Remove(element);
|
||||
element.Parent = null;
|
||||
}
|
||||
|
||||
public void AddExistingElement(ProfileElementViewModel element)
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a child to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.AddChild(element.ProfileElement);
|
||||
Children.Add(element);
|
||||
element.Parent = this;
|
||||
}
|
||||
|
||||
public void AddFolder()
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a folder to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.AddChild(new Folder(ProfileElement.Profile, ProfileElement, "New folder"));
|
||||
UpdateProfileElements();
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
public void AddLayer()
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a layer to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.AddChild(new Layer(ProfileElement.Profile, ProfileElement, "New layer"));
|
||||
UpdateProfileElements();
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public async Task RenameElement()
|
||||
{
|
||||
var result = await ProfileEditorViewModel.DialogService.ShowDialog<ProfileElementRenameViewModel>(
|
||||
new Dictionary<string, object> {{"profileElement", ProfileElement}}
|
||||
);
|
||||
if (result is string newName)
|
||||
{
|
||||
ProfileElement.Name = newName;
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public async Task DeleteElement()
|
||||
{
|
||||
var result = await ProfileEditorViewModel.DialogService.ShowConfirmDialog(
|
||||
"Delete profile element",
|
||||
"Are you sure you want to delete this element? This cannot be undone."
|
||||
);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
// Farewell, cruel world
|
||||
var parent = Parent;
|
||||
ProfileElement.Parent.RemoveChild(ProfileElement);
|
||||
parent.RemoveExistingElement(this);
|
||||
parent.UpdateProfileElements();
|
||||
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
private void UpdateProfileElements()
|
||||
{
|
||||
// Order the children
|
||||
var vmsList = Children.OrderBy(v => v.ProfileElement.Order).ToList();
|
||||
for (var index = 0; index < vmsList.Count; index++)
|
||||
{
|
||||
var profileElementViewModel = vmsList[index];
|
||||
Children.Move(Children.IndexOf(profileElementViewModel), index);
|
||||
}
|
||||
|
||||
// Ensure every child element has an up-to-date VM
|
||||
if (ProfileElement.Children != null)
|
||||
{
|
||||
foreach (var profileElement in ProfileElement.Children.OrderBy(c => c.Order))
|
||||
{
|
||||
ProfileElementViewModel existing = null;
|
||||
if (profileElement is Folder folder)
|
||||
{
|
||||
existing = Children.FirstOrDefault(p => p is FolderViewModel vm && vm.ProfileElement == folder);
|
||||
if (existing == null)
|
||||
Children.Add(new FolderViewModel(this, folder, ProfileEditorViewModel));
|
||||
}
|
||||
else if (profileElement is Layer layer)
|
||||
{
|
||||
existing = Children.FirstOrDefault(p => p is LayerViewModel vm && vm.ProfileElement == layer);
|
||||
if (existing == null)
|
||||
Children.Add(new LayerViewModel(this, layer, ProfileEditorViewModel));
|
||||
}
|
||||
|
||||
existing?.UpdateProfileElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,36 +9,45 @@
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||
xmlns:profileElements="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
|
||||
xmlns:profileElement="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type profileElements:ProfileElementsViewModel}}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TreeView Grid.Row="0"
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubheadingTextBlock}" Margin="10 5 0 -4">
|
||||
Profile elements
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||
</StackPanel>
|
||||
|
||||
<TreeView Grid.Row="1"
|
||||
ItemsSource="{Binding RootFolder.Children}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.DropHandler="{Binding}">
|
||||
<TreeView.Resources>
|
||||
<HierarchicalDataTemplate DataType="{x:Type profileEditor:FolderViewModel}" ItemsSource="{Binding Children}">
|
||||
<HierarchicalDataTemplate DataType="{x:Type profileElement:FolderViewModel}" ItemsSource="{Binding Children}">
|
||||
<ContentControl s:View.Model="{Binding}" />
|
||||
</HierarchicalDataTemplate>
|
||||
<HierarchicalDataTemplate DataType="{x:Type profileEditor:LayerViewModel}" ItemsSource="{Binding Children}">
|
||||
<HierarchicalDataTemplate DataType="{x:Type profileElement:LayerViewModel}" ItemsSource="{Binding Children}">
|
||||
<ContentControl s:View.Model="{Binding}" />
|
||||
</HierarchicalDataTemplate>
|
||||
</TreeView.Resources>
|
||||
</TreeView>
|
||||
|
||||
<StackPanel HorizontalAlignment="Right" Grid.Row="1" Orientation="Horizontal" Margin="8">
|
||||
<StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Margin="8">
|
||||
<Button Style="{StaticResource MaterialDesignToolButton}"
|
||||
Width="30"
|
||||
Padding="2 0 2 0"
|
||||
materialDesign:RippleAssist.IsCentered="True"
|
||||
ToolTip="Add new folder"
|
||||
ToolTip="Add new folder to root"
|
||||
Command="{s:Action AddFolder}">
|
||||
<materialDesign:PackIcon Kind="CreateNewFolder" />
|
||||
</Button>
|
||||
@ -46,7 +55,7 @@
|
||||
Width="30"
|
||||
Padding="2 0 2 0"
|
||||
materialDesign:RippleAssist.IsCentered="True"
|
||||
ToolTip="Add new layer"
|
||||
ToolTip="Add new layer to root"
|
||||
Command="{s:Action AddLayer}">
|
||||
<materialDesign:PackIcon Kind="LayersPlus" />
|
||||
</Button>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElement;
|
||||
using GongSolutions.Wpf.DragDrop;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
@ -21,14 +21,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
|
||||
switch (dragDropType)
|
||||
{
|
||||
case DragDropType.FolderAdd:
|
||||
case DragDropType.Add:
|
||||
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
|
||||
dropInfo.Effects = DragDropEffects.Move;
|
||||
break;
|
||||
case DragDropType.FolderInsertBefore:
|
||||
case DragDropType.FolderInsertAfter:
|
||||
case DragDropType.LayerInsertBefore:
|
||||
case DragDropType.LayerInsertAfter:
|
||||
case DragDropType.InsertBefore:
|
||||
case DragDropType.InsertAfter:
|
||||
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
|
||||
dropInfo.Effects = DragDropEffects.Move;
|
||||
break;
|
||||
@ -39,20 +37,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
{
|
||||
var source = (ProfileElementViewModel) dropInfo.Data;
|
||||
var target = (ProfileElementViewModel) dropInfo.TargetItem;
|
||||
|
||||
|
||||
var dragDropType = GetDragDropType(dropInfo);
|
||||
switch (dragDropType)
|
||||
{
|
||||
case DragDropType.FolderAdd:
|
||||
case DragDropType.Add:
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
((FolderViewModel) target).AddExistingElement(source);
|
||||
target.AddExistingElement(source);
|
||||
break;
|
||||
case DragDropType.FolderInsertBefore:
|
||||
case DragDropType.LayerInsertBefore:
|
||||
case DragDropType.InsertBefore:
|
||||
target.SetElementInFront(source);
|
||||
break;
|
||||
case DragDropType.FolderInsertAfter:
|
||||
case DragDropType.LayerInsertAfter:
|
||||
case DragDropType.InsertAfter:
|
||||
target.SetElementBehind(source);
|
||||
break;
|
||||
}
|
||||
@ -60,11 +56,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
ProfileEditorViewModel.OnProfileUpdated();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void AddFolder()
|
||||
{
|
||||
RootFolder?.AddFolder();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void AddLayer()
|
||||
{
|
||||
RootFolder?.AddLayer();
|
||||
@ -89,8 +87,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
|
||||
private static DragDropType GetDragDropType(IDropInfo dropInfo)
|
||||
{
|
||||
var source = dropInfo.Data as ProfileElementViewModel;
|
||||
var target = dropInfo.TargetItem as ProfileElementViewModel;
|
||||
var source = (ProfileElementViewModel) dropInfo.Data;
|
||||
var target = (ProfileElementViewModel) dropInfo.TargetItem;
|
||||
if (source == target)
|
||||
return DragDropType.None;
|
||||
|
||||
@ -102,35 +100,26 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
if (target is FolderViewModel)
|
||||
switch (dropInfo.InsertPosition)
|
||||
{
|
||||
if (dropInfo.InsertPosition >= RelativeInsertPosition.TargetItemCenter)
|
||||
return DragDropType.FolderAdd;
|
||||
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
|
||||
return DragDropType.FolderInsertBefore;
|
||||
return DragDropType.FolderInsertAfter;
|
||||
case RelativeInsertPosition.AfterTargetItem | RelativeInsertPosition.TargetItemCenter:
|
||||
case RelativeInsertPosition.BeforeTargetItem | RelativeInsertPosition.TargetItemCenter:
|
||||
return target.SupportsChildren ? DragDropType.Add : DragDropType.None;
|
||||
case RelativeInsertPosition.BeforeTargetItem:
|
||||
return DragDropType.InsertBefore;
|
||||
case RelativeInsertPosition.AfterTargetItem:
|
||||
return DragDropType.InsertAfter;
|
||||
default:
|
||||
return DragDropType.None;
|
||||
}
|
||||
|
||||
if (target is LayerViewModel)
|
||||
{
|
||||
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
|
||||
return DragDropType.LayerInsertBefore;
|
||||
if (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem)
|
||||
return DragDropType.LayerInsertAfter;
|
||||
return DragDropType.None;
|
||||
}
|
||||
|
||||
return DragDropType.None;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DragDropType
|
||||
{
|
||||
None,
|
||||
FolderAdd,
|
||||
FolderInsertBefore,
|
||||
FolderInsertAfter,
|
||||
LayerInsertBefore,
|
||||
LayerInsertAfter
|
||||
Add,
|
||||
InsertBefore,
|
||||
InsertAfter
|
||||
}
|
||||
}
|
||||
@ -68,14 +68,22 @@
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.25" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.25">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" >
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
@ -84,10 +92,10 @@
|
||||
</Style>
|
||||
</Path.Style>
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{StaticResource Accent400}" Opacity="0.65" />
|
||||
<SolidColorBrush Opacity="0.65" />
|
||||
</Path.Fill>
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Color="{StaticResource Accent400}"></SolidColorBrush>
|
||||
<SolidColorBrush />
|
||||
</Path.Stroke>
|
||||
</Path>
|
||||
</Canvas>
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
MouseDown="{s:Action EditorGridMouseClick}"
|
||||
MouseMove="{s:Action EditorGridMouseMove}"
|
||||
Cursor="{Binding Cursor}">
|
||||
|
||||
<Grid.Background>
|
||||
<VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute">
|
||||
<VisualBrush.Visual>
|
||||
@ -81,6 +82,37 @@
|
||||
</EventTrigger>
|
||||
</Grid.Triggers>
|
||||
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Create new layer for selection" Command="{s:Action CreateLayer}" CommandParameter="{Binding}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="LayersPlus" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Apply selection to layer" Command="{s:Action ApplyToLayer}" CommandParameter="{Binding}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Selection" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Select all" Command="{s:Action SelectAll}" CommandParameter="{Binding}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="SelectAll" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Inverse selection" Command="{s:Action InverseSelection}" CommandParameter="{Binding}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="SelectInverse" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Clear selection" Command="{s:Action ClearSelection}" CommandParameter="{Binding}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="SelectOff" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
|
||||
<Grid Name="EditorDisplayGrid">
|
||||
<Grid.RenderTransform>
|
||||
<TransformGroup>
|
||||
@ -119,8 +151,21 @@
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
|
||||
<StackPanel ZIndex="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10">
|
||||
<materialDesign:Card Padding="8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}">
|
||||
Highlight selected layer
|
||||
</CheckBox>
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Margin="10 0 0 0">
|
||||
Pause visualization on focus loss
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Right"
|
||||
Margin="0, 0, 15, 15">
|
||||
Margin="10" ZIndex="1">
|
||||
<Slider Margin="0,0,14,0"
|
||||
Orientation="Vertical"
|
||||
Minimum="10"
|
||||
|
||||
@ -35,8 +35,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
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 targetFpsSetting = settingsService.GetSetting("Core.TargetFrameRate", 25);
|
||||
var editorTargetFpsSetting = settingsService.GetSetting("ProfileEditor.TargetFrameRate", 15);
|
||||
var targetFps = Math.Min(targetFpsSetting.Value, editorTargetFpsSetting.Value);
|
||||
_updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / targetFps};
|
||||
_updateTrigger.Update += UpdateLeds;
|
||||
@ -122,9 +122,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
private Point _mouseDragStartPoint;
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void EditorGridMouseClick(object sender, MouseEventArgs e)
|
||||
public void EditorGridMouseClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (IsPanKeyDown())
|
||||
if (IsPanKeyDown() || e.ChangedButton == MouseButton.Right)
|
||||
return;
|
||||
|
||||
var position = e.GetPosition((IInputElement) sender);
|
||||
|
||||
@ -35,21 +35,21 @@ namespace Artemis.UI.Screens.Settings
|
||||
|
||||
public double RenderScale
|
||||
{
|
||||
get => _settingsService.GetSetting("RenderScale", 1.0).Value;
|
||||
get => _settingsService.GetSetting("Core.RenderScale", 1.0).Value;
|
||||
set
|
||||
{
|
||||
_settingsService.GetSetting("RenderScale", 1.0).Value = value;
|
||||
_settingsService.GetSetting("RenderScale", 1.0).Save();
|
||||
_settingsService.GetSetting("Core.RenderScale", 1.0).Value = value;
|
||||
_settingsService.GetSetting("Core.RenderScale", 1.0).Save();
|
||||
}
|
||||
}
|
||||
|
||||
public int TargetFrameRate
|
||||
{
|
||||
get => _settingsService.GetSetting("TargetFrameRate", 25).Value;
|
||||
get => _settingsService.GetSetting("Core.TargetFrameRate", 25).Value;
|
||||
set
|
||||
{
|
||||
_settingsService.GetSetting("TargetFrameRate", 25).Value = value;
|
||||
_settingsService.GetSetting("TargetFrameRate", 25).Save();
|
||||
_settingsService.GetSetting("Core.TargetFrameRate", 25).Value = value;
|
||||
_settingsService.GetSetting("Core.TargetFrameRate", 25).Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -67,13 +67,5 @@ namespace Artemis.UI.Stylet
|
||||
if (Kernel != null)
|
||||
Kernel.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
var logger = Kernel.Get<ILogger>();
|
||||
logger.Fatal(e.Exception, "Fatal exception, shutting down.");
|
||||
|
||||
base.OnUnhandledException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user