mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Profiles - Reworked profile system
Sidebar - Redesigned sidebar with customizable categories Profiles - Added the ability to configure custom profile icons Profiles - Added the ability to activate multiple profiles for modules at once Profiles - Added the ability to create profiles for no modules Profiles - Added the ability to suspend a profile or an entire category Profiles - Added profile activation conditions Profiles - Added file-based importing/exporting Profile editor - Condensed UI, removed tabs Profile editor - Disable condition operators until a left-side is picked
This commit is contained in:
1 parent
4152c290d2
commit
ceeaa4bf6d
164 files changed
+5019
-4220
No files matched your search
@@ -1,26 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Modules.ModuleRootView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:modules="clr-namespace:Artemis.UI.Screens.Modules"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance modules:ModuleRootViewModel}">
|
||||
|
||||
<TabControl Margin="0 -1 0 0"
|
||||
ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding ActiveItem}"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Style="{StaticResource MaterialDesignTabControl}">
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
|
||||
<ContentControl s:View.Model="{Binding IsAsync=True}" TextElement.Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
</TabControl>
|
||||
</UserControl>
|
||||
@@ -1,57 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Modules;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Modules
|
||||
{
|
||||
public class ModuleRootViewModel : Conductor<Screen>.Collection.OneActive
|
||||
{
|
||||
private readonly IModuleVmFactory _moduleVmFactory;
|
||||
|
||||
public ModuleRootViewModel(Module module, IModuleVmFactory moduleVmFactory)
|
||||
{
|
||||
DisplayName = module?.DisplayName;
|
||||
Module = module;
|
||||
|
||||
_moduleVmFactory = moduleVmFactory;
|
||||
}
|
||||
|
||||
public Module Module { get; }
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
AddTabs();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
private void AddTabs()
|
||||
{
|
||||
// Create the profile editor and module VMs
|
||||
if (Module is ProfileModule profileModule)
|
||||
Items.Add(_moduleVmFactory.CreateProfileEditorViewModel(profileModule));
|
||||
|
||||
if (Module.ActivationRequirements.Any())
|
||||
Items.Add(_moduleVmFactory.CreateActivationRequirementsViewModel(Module));
|
||||
|
||||
if (Module.ModuleTabs != null)
|
||||
{
|
||||
List<ModuleTab> moduleTabs = new(Module.ModuleTabs);
|
||||
foreach (ModuleTab moduleTab in moduleTabs.Where(m => m != null))
|
||||
{
|
||||
ConstructorArgument module = new("module", Module);
|
||||
ConstructorArgument displayName = new("displayName", DisplayName);
|
||||
|
||||
ModuleViewModel viewModel = (ModuleViewModel) Module.Plugin.Kernel.Get(moduleTab.Type, module, displayName);
|
||||
Items.Add(viewModel);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveItem = Items.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Modules.Tabs.ActivationRequirementView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Modules.Tabs"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance tabs:ActivationRequirementViewModel}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Text="{Binding RequirementName}" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding RequirementDescription}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}"
|
||||
Focusable="False"
|
||||
IsHitTestVisible="False"
|
||||
IsChecked="{Binding RequirementMet}">
|
||||
<ToggleButton.Content>
|
||||
<Border Background="#E74C4C" Width="32" Height="32">
|
||||
<materialDesign:PackIcon Kind="Close" VerticalAlignment="Center" HorizontalAlignment="Center" />
|
||||
</Border>
|
||||
</ToggleButton.Content>
|
||||
<materialDesign:ToggleButtonAssist.OnContent>
|
||||
<materialDesign:PackIcon Kind="Check" />
|
||||
</materialDesign:ToggleButtonAssist.OnContent>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,54 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Modules.Tabs.ActivationRequirementsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Modules.Tabs"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:ActivationRequirementsViewModel}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="15" MaxWidth="800">
|
||||
<!-- General settings -->
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Activation requirements</TextBlock>
|
||||
<TextBlock Margin="0 0 0 15" TextWrapping="Wrap" Style="{StaticResource MaterialDesignTextBlock}">
|
||||
This module has built-in activation requirements and won't activate until
|
||||
<Run Text="{Binding ActivationType}" FontWeight="Medium" Foreground="{StaticResource SecondaryHueMidBrush}" />. <LineBreak />
|
||||
These requirements allow the module creator to decide when the module is activated and you cannot override them.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
TextWrapping="Wrap">
|
||||
Note: While you have the profile editor open the module is always activated and any other modules are deactivated.
|
||||
</TextBlock>
|
||||
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||
|
||||
<ItemsControl ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<Separator Margin="0 -10">
|
||||
<Separator.Style>
|
||||
<Style TargetType="Separator" BasedOn="{StaticResource MaterialDesignSeparator}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Separator.Style>
|
||||
</Separator>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" Margin="20" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Modules.Tabs
|
||||
{
|
||||
public class ActivationRequirementsViewModel : Conductor<ActivationRequirementViewModel>.Collection.AllActive
|
||||
{
|
||||
private readonly IModuleVmFactory _moduleVmFactory;
|
||||
|
||||
public ActivationRequirementsViewModel(Module module, IModuleVmFactory moduleVmFactory)
|
||||
{
|
||||
_moduleVmFactory = moduleVmFactory;
|
||||
|
||||
DisplayName = "ACTIVATION REQUIREMENTS";
|
||||
Module = module;
|
||||
|
||||
ActivationType = Module.ActivationRequirementMode == ActivationRequirementType.All
|
||||
? "all requirements are met"
|
||||
: "any requirement is met";
|
||||
}
|
||||
|
||||
public Module Module { get; }
|
||||
|
||||
public string ActivationType { get; set; }
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
Items.Clear();
|
||||
Items.AddRange(Module.ActivationRequirements.Select(_moduleVmFactory.CreateActivationRequirementViewModel));
|
||||
|
||||
base.OnActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.News.NewsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16">
|
||||
<materialDesign:PackIcon Kind="Crane" Width="250" Height="250" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
|
||||
News is not yet implemented
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
|
||||
The news page will keep you up-to-date with the latest developments in the Artemis community. <LineBreak />
|
||||
You'll find the latest patch notes here and see featured workshop contributions.<LineBreak /><LineBreak />
|
||||
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,12 +0,0 @@
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.News
|
||||
{
|
||||
public class NewsViewModel : Screen, IMainScreenViewModel
|
||||
{
|
||||
public NewsViewModel()
|
||||
{
|
||||
DisplayName = "News";
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
-9
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Input;
|
||||
@@ -16,6 +17,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
{
|
||||
private readonly IConditionOperatorService _conditionOperatorService;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly List<Module> _modules;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private DataModelStaticViewModel _rightSideInputViewModel;
|
||||
private DataModelDynamicViewModel _rightSideSelectionViewModel;
|
||||
@@ -25,11 +27,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
|
||||
protected DataModelConditionPredicateViewModel(
|
||||
DataModelConditionPredicate dataModelConditionPredicate,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService) : base(dataModelConditionPredicate)
|
||||
{
|
||||
_modules = modules;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_conditionOperatorService = conditionOperatorService;
|
||||
@@ -44,6 +48,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
public DataModelConditionPredicate DataModelConditionPredicate => (DataModelConditionPredicate) Model;
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public bool CanSelectOperator => DataModelConditionPredicate.LeftPath is {IsValid: true};
|
||||
|
||||
public BaseConditionOperator SelectedOperator
|
||||
{
|
||||
get => _selectedOperator;
|
||||
@@ -75,12 +81,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_modules);
|
||||
LeftSideSelectionViewModel.PropertySelected += LeftSideOnPropertySelected;
|
||||
if (LeftSideColor != null)
|
||||
LeftSideSelectionViewModel.ButtonBrush = LeftSideColor;
|
||||
@@ -107,10 +113,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
else if (!Operators.Contains(DataModelConditionPredicate.Operator))
|
||||
DataModelConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.Description == DataModelConditionPredicate.Operator.Description) ?? Operators.FirstOrDefault());
|
||||
|
||||
NotifyOfPropertyChange(nameof(CanSelectOperator));
|
||||
SelectedOperator = DataModelConditionPredicate.Operator;
|
||||
|
||||
// Without a selected operator or one that supports a right side, leave the right side input empty
|
||||
if (SelectedOperator == null || SelectedOperator.RightSideType == null)
|
||||
if (SelectedOperator?.RightSideType == null)
|
||||
{
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
@@ -132,7 +139,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
DisposeRightSideDynamicViewModel();
|
||||
if (RightSideInputViewModel == null)
|
||||
CreateRightSideInputViewModel();
|
||||
|
||||
|
||||
Type preferredType = DataModelConditionPredicate.GetPreferredRightSideType();
|
||||
if (preferredType != null && RightSideInputViewModel.TargetType != preferredType)
|
||||
RightSideInputViewModel.UpdateTargetType(preferredType);
|
||||
@@ -149,7 +156,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
return;
|
||||
|
||||
DataModelConditionPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
SelectedOperator = DataModelConditionPredicate.Operator;
|
||||
Update();
|
||||
@@ -158,7 +165,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
public void ApplyRightSideDynamic()
|
||||
{
|
||||
DataModelConditionPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
@@ -166,7 +173,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
public void ApplyRightSideStatic(object value)
|
||||
{
|
||||
DataModelConditionPredicate.UpdateRightSideStatic(value);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
@@ -174,7 +181,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
public void ApplyOperator()
|
||||
{
|
||||
DataModelConditionPredicate.UpdateOperator(SelectedOperator);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
@@ -196,6 +203,26 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
ApplyOperator();
|
||||
}
|
||||
|
||||
public override void UpdateModules()
|
||||
{
|
||||
if (LeftSideSelectionViewModel != null)
|
||||
{
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel = null;
|
||||
}
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
|
||||
// If the modules changed the paths may no longer be valid if they targeted a module no longer available, in that case clear the path
|
||||
if (DataModelConditionPredicate.LeftPath?.Target != null && !DataModelConditionPredicate.LeftPath.Target.IsExpansion && !_modules.Contains(DataModelConditionPredicate.LeftPath.Target.Module))
|
||||
DataModelConditionPredicate.UpdateLeftSide(null);
|
||||
if (DataModelConditionPredicate.RightPath?.Target != null && !DataModelConditionPredicate.RightPath.Target.IsExpansion && !_modules.Contains(DataModelConditionPredicate.RightPath.Target.Module))
|
||||
DataModelConditionPredicate.UpdateRightSideDynamic(null);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
@@ -227,7 +254,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
|
||||
private void CreateRightSideSelectionViewModel()
|
||||
{
|
||||
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_modules);
|
||||
RightSideSelectionViewModel.ButtonBrush = (SolidColorBrush) Application.Current.FindResource("PrimaryHueMidBrush");
|
||||
RightSideSelectionViewModel.DisplaySwitchButton = true;
|
||||
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
|
||||
|
||||
+2
@@ -63,5 +63,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
groupViewModel.ConvertToPredicate(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void UpdateModules();
|
||||
}
|
||||
}
|
||||
+14
-3
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
@@ -14,15 +15,18 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly List<Module> _modules;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private DateTime _lastTrigger;
|
||||
private string _triggerPastParticiple;
|
||||
|
||||
public DataModelConditionEventViewModel(DataModelConditionEvent dataModelConditionEvent,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IDataModelConditionsVmFactory dataModelConditionsVmFactory) : base(dataModelConditionEvent)
|
||||
{
|
||||
_modules = modules;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
||||
@@ -46,7 +50,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_modules);
|
||||
LeftSideSelectionViewModel.PropertySelected += LeftSideSelectionViewModelOnPropertySelected;
|
||||
LeftSideSelectionViewModel.LoadEventChildren = false;
|
||||
|
||||
@@ -82,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
if (!(childModel is DataModelConditionGroup dataModelConditionGroup))
|
||||
continue;
|
||||
|
||||
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.Event);
|
||||
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.Event, _modules);
|
||||
viewModel.IsRootGroup = true;
|
||||
viewModels.Add(viewModel);
|
||||
}
|
||||
@@ -103,11 +107,18 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
public void ApplyEvent()
|
||||
{
|
||||
DataModelConditionEvent.UpdateEvent(LeftSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override void UpdateModules()
|
||||
{
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideSelectionViewModelOnPropertySelected;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
+49
-10
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
@@ -14,17 +16,23 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
public class DataModelConditionGroupViewModel : DataModelConditionViewModel
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly List<Module> _modules;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _isEventGroup;
|
||||
private bool _isRootGroup;
|
||||
|
||||
public DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup,
|
||||
ConditionGroupType groupType,
|
||||
List<Module> modules,
|
||||
ICoreService coreService,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelConditionsVmFactory dataModelConditionsVmFactory)
|
||||
: base(dataModelConditionGroup)
|
||||
{
|
||||
GroupType = groupType;
|
||||
_modules = modules;
|
||||
_coreService = coreService;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
||||
|
||||
@@ -66,7 +74,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionGroup.BooleanOperator = enumValue;
|
||||
NotifyOfPropertyChange(nameof(SelectedBooleanOperator));
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddCondition()
|
||||
@@ -87,7 +95,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
}
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddEventCondition()
|
||||
@@ -104,7 +112,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionGroup.AddChild(new DataModelConditionEvent(DataModelConditionGroup), index);
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddGroup()
|
||||
@@ -112,7 +120,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionGroup.AddChild(new DataModelConditionGroup(DataModelConditionGroup));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
@@ -131,22 +139,22 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
switch (childModel)
|
||||
{
|
||||
case DataModelConditionGroup dataModelConditionGroup:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, GroupType));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, GroupType, _modules));
|
||||
break;
|
||||
case DataModelConditionList dataModelConditionList:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionListViewModel(dataModelConditionList));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionListViewModel(dataModelConditionList, _modules));
|
||||
break;
|
||||
case DataModelConditionEvent dataModelConditionEvent:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionEventViewModel(dataModelConditionEvent));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionEventViewModel(dataModelConditionEvent, _modules));
|
||||
break;
|
||||
case DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionGeneralPredicateViewModel(dataModelConditionGeneralPredicate));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionGeneralPredicateViewModel(dataModelConditionGeneralPredicate, _modules));
|
||||
break;
|
||||
case DataModelConditionListPredicate dataModelConditionListPredicate:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionListPredicateViewModel(dataModelConditionListPredicate));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionListPredicateViewModel(dataModelConditionListPredicate, _modules));
|
||||
break;
|
||||
case DataModelConditionEventPredicate dataModelConditionEventPredicate:
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionEventPredicateViewModel(dataModelConditionEventPredicate));
|
||||
Items.Add(_dataModelConditionsVmFactory.DataModelConditionEventPredicateViewModel(dataModelConditionEventPredicate, _modules));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -173,6 +181,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
dataModelConditionViewModel.Evaluate();
|
||||
}
|
||||
|
||||
public override void UpdateModules()
|
||||
{
|
||||
foreach (DataModelConditionViewModel dataModelConditionViewModel in Items)
|
||||
dataModelConditionViewModel.UpdateModules();
|
||||
}
|
||||
|
||||
public void ConvertToConditionList(DataModelConditionViewModel predicateViewModel)
|
||||
{
|
||||
// Store the old index and remove the old predicate
|
||||
@@ -203,8 +217,33 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
Update();
|
||||
}
|
||||
|
||||
private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
if (IsRootGroup)
|
||||
Evaluate();
|
||||
}
|
||||
|
||||
public event EventHandler Updated;
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
base.OnInitialActivate();
|
||||
Update();
|
||||
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual void OnUpdated()
|
||||
{
|
||||
Updated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
+20
-11
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
@@ -16,14 +16,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly List<Module> _modules;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
public DataModelConditionListViewModel(
|
||||
DataModelConditionList dataModelConditionList,
|
||||
public DataModelConditionListViewModel(DataModelConditionList dataModelConditionList,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IDataModelConditionsVmFactory dataModelConditionsVmFactory) : base(dataModelConditionList)
|
||||
{
|
||||
_modules = modules;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
||||
@@ -39,7 +41,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionList.ListOperator = enumValue;
|
||||
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddCondition()
|
||||
@@ -47,7 +49,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionList.AddChild(new DataModelConditionGeneralPredicate(DataModelConditionList, ProfileRightSideType.Dynamic));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddGroup()
|
||||
@@ -55,25 +57,32 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionList.AddChild(new DataModelConditionGroup(DataModelConditionList));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
IsConditionMet = DataModelConditionList.Evaluate();
|
||||
foreach (DataModelConditionViewModel dataModelConditionViewModel in Items)
|
||||
foreach (DataModelConditionViewModel dataModelConditionViewModel in Items)
|
||||
dataModelConditionViewModel.Evaluate();
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UpdateModules()
|
||||
{
|
||||
foreach (DataModelConditionViewModel dataModelConditionViewModel in Items)
|
||||
dataModelConditionViewModel.UpdateModules();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_modules);
|
||||
LeftSideSelectionViewModel.PropertySelected += LeftSideSelectionViewModelOnPropertySelected;
|
||||
|
||||
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
|
||||
@@ -96,7 +105,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
return;
|
||||
|
||||
DataModelConditionList.UpdateList(LeftSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
@@ -120,7 +129,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
if (!(childModel is DataModelConditionGroup dataModelConditionGroup))
|
||||
continue;
|
||||
|
||||
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.List);
|
||||
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.List, _modules);
|
||||
viewModel.IsRootGroup = true;
|
||||
viewModels.Add(viewModel);
|
||||
}
|
||||
|
||||
+1
@@ -55,6 +55,7 @@
|
||||
Background="#7B7B7B"
|
||||
BorderBrush="#7B7B7B"
|
||||
Content="{Binding SelectedOperator.Description}"
|
||||
IsEnabled="{Binding CanSelectOperator}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding Operators}">
|
||||
|
||||
+3
-1
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
@@ -16,11 +17,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
|
||||
public DataModelConditionEventPredicateViewModel(DataModelConditionEventPredicate dataModelConditionEventPredicate,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService)
|
||||
: base(dataModelConditionEventPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
: base(dataModelConditionEventPredicate, modules, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
|
||||
|
||||
+1
@@ -56,6 +56,7 @@
|
||||
Background="#7B7B7B"
|
||||
BorderBrush="#7B7B7B"
|
||||
Content="{Binding SelectedOperator.Description}"
|
||||
IsEnabled="{Binding CanSelectOperator}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding Operators}">
|
||||
|
||||
+3
-1
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
@@ -14,11 +15,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
|
||||
public DataModelConditionGeneralPredicateViewModel(DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService)
|
||||
: base(dataModelConditionGeneralPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
: base(dataModelConditionGeneralPredicate, modules, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
}
|
||||
|
||||
+1
@@ -55,6 +55,7 @@
|
||||
Background="#7B7B7B"
|
||||
BorderBrush="#7B7B7B"
|
||||
Content="{Binding SelectedOperator.Description}"
|
||||
IsEnabled="{Binding CanSelectOperator}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding Operators}">
|
||||
|
||||
+14
-7
@@ -3,8 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@@ -16,11 +16,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
|
||||
public DataModelConditionListPredicateViewModel(DataModelConditionListPredicate dataModelConditionListPredicate,
|
||||
List<Module> modules,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService)
|
||||
: base(dataModelConditionListPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
: base(dataModelConditionListPredicate, modules, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
|
||||
@@ -44,6 +45,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
}
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void UpdateModules()
|
||||
{
|
||||
foreach (DataModelConditionViewModel dataModelConditionViewModel in Items)
|
||||
dataModelConditionViewModel.UpdateModules();
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
base.OnInitialActivate();
|
||||
@@ -81,10 +93,5 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
return wrapper.CreateViewModel(_dataModelUIService, new DataModelUpdateConfiguration(true));
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Dialogs.ProfileCreateView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="213.053" d:DesignWidth="254.425">
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
|
||||
Add a new profile
|
||||
</TextBlock>
|
||||
|
||||
<TextBox materialDesign:HintAssist.Hint="Profile name"
|
||||
Margin="0 8 0 16"
|
||||
Width="300"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding ProfileName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 0 8 0" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 0 0 0" Command="{s:Action Accept}">
|
||||
ACCEPT
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Dialogs
|
||||
{
|
||||
public class ProfileCreateViewModel : DialogViewModelBase
|
||||
{
|
||||
private string _profileName;
|
||||
|
||||
public ProfileCreateViewModel(IModelValidator<ProfileCreateViewModel> validator) : base(validator)
|
||||
{
|
||||
}
|
||||
|
||||
public string ProfileName
|
||||
{
|
||||
get => _profileName;
|
||||
set => SetAndNotify(ref _profileName, value);
|
||||
}
|
||||
|
||||
public async Task Accept()
|
||||
{
|
||||
await ValidateAsync();
|
||||
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
Session.Close(ProfileName);
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfileCreateViewModelValidator : AbstractValidator<ProfileCreateViewModel>
|
||||
{
|
||||
public ProfileCreateViewModelValidator()
|
||||
{
|
||||
RuleFor(m => m.ProfileName).NotEmpty().WithMessage("Profile name may not be empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Dialogs
|
||||
{
|
||||
public class ProfileEditViewModel : DialogViewModelBase
|
||||
{
|
||||
private string _profileName;
|
||||
|
||||
public ProfileEditViewModel(IModelValidator<ProfileEditViewModel> validator, Profile profile) : base(validator)
|
||||
{
|
||||
ProfileName = profile.Name;
|
||||
}
|
||||
|
||||
public string ProfileName
|
||||
{
|
||||
get => _profileName;
|
||||
set => SetAndNotify(ref _profileName, value);
|
||||
}
|
||||
|
||||
public async Task Accept()
|
||||
{
|
||||
await ValidateAsync();
|
||||
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
Session.Close(ProfileName);
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfileEditViewModelValidator : AbstractValidator<ProfileEditViewModel>
|
||||
{
|
||||
public ProfileEditViewModelValidator()
|
||||
{
|
||||
RuleFor(m => m.ProfileName).NotEmpty().WithMessage("Profile name may not be empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Dialogs.ProfileExportView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Margin="16" Width="500">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Grid.Row="0">
|
||||
Export current profile
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Margin="0 10"
|
||||
TextWrapping="Wrap"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}">
|
||||
It looks like you have not set up any profile adaption hints. This means Artemis can't do much to make your profile look good on a different surface other than try finding the same LEDs as you have.
|
||||
<LineBreak/><LineBreak/>
|
||||
To configure adaption hints, right-click on a layer and choose <materialDesign:PackIcon Kind="AutoFix" /> <Run FontWeight="Bold">View Adaption Hints</Run>.
|
||||
<LineBreak/><LineBreak/>
|
||||
To learn more about profile adaption, check out
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}" RequestNavigate="{s:Action OpenHyperlink}" NavigateUri="https://wiki.artemis-rgb.com/guides/user/profiles/layers/adaption-hints">
|
||||
this wiki article
|
||||
</Hyperlink>.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="2">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0" Command="{s:Action Accept}">
|
||||
EXPORT ANYWAY
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,49 +0,0 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Navigation;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Dialogs
|
||||
{
|
||||
public class ProfileExportViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly IMessageService _messageService;
|
||||
|
||||
public ProfileExportViewModel(ProfileDescriptor profileDescriptor, IProfileService profileService, IMessageService messageService)
|
||||
{
|
||||
ProfileDescriptor = profileDescriptor;
|
||||
|
||||
_profileService = profileService;
|
||||
_messageService = messageService;
|
||||
}
|
||||
|
||||
public ProfileDescriptor ProfileDescriptor { get; }
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
// TODO: If the profile has hints on all layers, call Accept
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void OpenHyperlink(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
Core.Utilities.OpenUrl(e.Uri.AbsoluteUri);
|
||||
}
|
||||
|
||||
public void Accept()
|
||||
{
|
||||
string encoded = _profileService.ExportProfile(ProfileDescriptor);
|
||||
Clipboard.SetText(encoded);
|
||||
_messageService.ShowMessage("Profile contents exported to clipboard.");
|
||||
|
||||
Session.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Dialogs.ProfileImportView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Margin="16" Width="800">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Grid.Row="0">
|
||||
Import profile to current module
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Margin="0 10"
|
||||
TextWrapping="Wrap"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}">
|
||||
Please note that importing profiles like this is placeholder functionality. The idea is that this will eventually happen via the workshop.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="2"
|
||||
Margin="0 10"
|
||||
TextWrapping="Wrap"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}">
|
||||
The workshop will include tools to make profiles convert easily and look good on different layouts.
|
||||
That means right now when you import this profile unless you have the exact same setup as
|
||||
the person who exported it, you'll have to select LEDs for each layer in the profile.
|
||||
</TextBlock>
|
||||
|
||||
<TextBox Grid.Row="3"
|
||||
Text="{Binding ProfileJson}"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
FontFamily="Consolas"
|
||||
VerticalAlignment="Top"
|
||||
Height="400"
|
||||
AcceptsReturn="True"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
materialDesign:HintAssist.Hint="Paste profile JSON here"
|
||||
Margin="16" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="4">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0" Command="{s:Action Accept}">
|
||||
I UNDERSTAND, IMPORT
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,37 +0,0 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Dialogs
|
||||
{
|
||||
public class ProfileImportViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly IMessageService _messageService;
|
||||
private string _profileJson;
|
||||
|
||||
public ProfileImportViewModel(ProfileModule profileModule, IProfileService profileService, IMessageService messageService)
|
||||
{
|
||||
ProfileModule = profileModule;
|
||||
|
||||
_profileService = profileService;
|
||||
_messageService = messageService;
|
||||
}
|
||||
|
||||
public ProfileModule ProfileModule { get; }
|
||||
|
||||
public string ProfileJson
|
||||
{
|
||||
get => _profileJson;
|
||||
set => SetAndNotify(ref _profileJson, value);
|
||||
}
|
||||
|
||||
public void Accept()
|
||||
{
|
||||
ProfileDescriptor descriptor = _profileService.ImportProfile(ProfileJson, ProfileModule);
|
||||
_messageService.ShowMessage("Profile imported.");
|
||||
Session.Close(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-19
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions;
|
||||
@@ -14,17 +16,15 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
public class DisplayConditionsViewModel : Conductor<DataModelConditionGroupViewModel>, IProfileEditorPanelViewModel
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private RenderProfileElement _renderProfileElement;
|
||||
private bool _displayStartHint;
|
||||
private bool _isEventCondition;
|
||||
|
||||
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDataModelConditionsVmFactory dataModelConditionsVmFactory, ICoreService coreService)
|
||||
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDataModelConditionsVmFactory dataModelConditionsVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
||||
_coreService = coreService;
|
||||
}
|
||||
|
||||
public bool DisplayStartHint
|
||||
@@ -59,7 +59,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
TimelinePlayMode playMode = value ? TimelinePlayMode.Repeat : TimelinePlayMode.Once;
|
||||
if (RenderProfileElement == null || RenderProfileElement?.Timeline.PlayMode == playMode) return;
|
||||
RenderProfileElement.Timeline.PlayMode = playMode;
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
TimelineStopMode stopMode = value ? TimelineStopMode.Finish : TimelineStopMode.SkipToEnd;
|
||||
if (RenderProfileElement == null || RenderProfileElement?.Timeline.StopMode == stopMode) return;
|
||||
RenderProfileElement.Timeline.StopMode = stopMode;
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
if (RenderProfileElement == null || RenderProfileElement?.Timeline.EventOverlapMode == value) return;
|
||||
RenderProfileElement.Timeline.EventOverlapMode = value;
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,19 +90,17 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
||||
_profileEditorService.SelectedProfileElementChanged += SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
|
||||
_profileEditorService.SelectedProfileElementChanged -= SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
private void SelectedProfileEditorServiceOnSelectedProfileElementChanged(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (RenderProfileElement != null)
|
||||
{
|
||||
@@ -127,9 +125,11 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
if (e.RenderProfileElement.DisplayCondition == null)
|
||||
e.RenderProfileElement.DisplayCondition = new DataModelConditionGroup(null);
|
||||
|
||||
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(e.RenderProfileElement.DisplayCondition, ConditionGroupType.General);
|
||||
List<Module> modules = new();
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Module != null)
|
||||
modules.Add(_profileEditorService.SelectedProfileConfiguration.Module);
|
||||
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(e.RenderProfileElement.DisplayCondition, ConditionGroupType.General, modules);
|
||||
ActiveItem.IsRootGroup = true;
|
||||
ActiveItem.Update();
|
||||
|
||||
DisplayStartHint = !RenderProfileElement.DisplayCondition.Children.Any();
|
||||
IsEventCondition = RenderProfileElement.DisplayCondition.Children.Any(c => c is DataModelConditionEvent);
|
||||
@@ -146,11 +146,6 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
NotifyOfPropertyChange(nameof(EventOverlapMode));
|
||||
}
|
||||
|
||||
private void CoreServiceOnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
ActiveItem?.Evaluate();
|
||||
}
|
||||
|
||||
private void DisplayConditionOnChildrenModified(object sender, EventArgs e)
|
||||
{
|
||||
DisplayStartHint = !RenderProfileElement.DisplayCondition.Children.Any();
|
||||
@@ -159,7 +154,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
|
||||
public void EventTriggerModeSelected()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-19
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@@ -15,16 +14,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
IDataBindingModeViewModel
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _updating;
|
||||
|
||||
public ConditionalDataBindingModeViewModel(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding,
|
||||
ICoreService coreService,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataBindingsVmFactory dataBindingsVmFactory)
|
||||
{
|
||||
_coreService = coreService;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataBindingsVmFactory = dataBindingsVmFactory;
|
||||
|
||||
@@ -41,7 +37,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
DataBindingConditionViewModel<TLayerProperty, TProperty> viewModel = Items.First(c => c.DataBindingCondition == condition);
|
||||
viewModel.ActiveItem.AddCondition();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void RemoveCondition(DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition)
|
||||
@@ -52,22 +48,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
Initialize();
|
||||
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
private void CoreServiceOnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
foreach (DataBindingConditionViewModel<TLayerProperty, TProperty> dataBindingConditionViewModel in Items)
|
||||
dataBindingConditionViewModel.Evaluate();
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
_updating = true;
|
||||
@@ -111,7 +94,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
|
||||
ConditionalDataBinding.ApplyOrder();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void ConditionalDataBindingOnConditionsUpdated(object sender, EventArgs e)
|
||||
|
||||
+7
-7
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions;
|
||||
using Artemis.UI.Shared;
|
||||
@@ -34,7 +36,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
base.OnInitialActivate();
|
||||
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(DataBindingCondition.Condition, ConditionGroupType.General);
|
||||
List<Module> modules = new();
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Module != null)
|
||||
modules.Add(_profileEditorService.SelectedProfileConfiguration.Module);
|
||||
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(DataBindingCondition.Condition, ConditionGroupType.General, modules);
|
||||
ActiveItem.IsRootGroup = true;
|
||||
|
||||
ActiveItem.Update();
|
||||
@@ -54,12 +59,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
private void ValueViewModelOnValueUpdated(object sender, DataModelInputStaticEventArgs e)
|
||||
{
|
||||
DataBindingCondition.Value = (TProperty) Convert.ChangeType(e.Value, typeof(TProperty));
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Evaluate()
|
||||
{
|
||||
ActiveItem?.Evaluate();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddCondition()
|
||||
|
||||
+5
-5
@@ -178,7 +178,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
Registration.DataBinding.EasingFunction = SelectedEasingViewModel?.EasingFunction ?? Easings.Functions.Linear;
|
||||
}
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
Update();
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
}
|
||||
|
||||
CreateDataBindingModeModeViewModel();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void UpdateTestResult()
|
||||
@@ -243,7 +243,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
return;
|
||||
|
||||
Registration.LayerProperty.EnableDataBinding(Registration);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void RemoveDataBinding()
|
||||
@@ -255,7 +255,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
Registration.LayerProperty.DisableDataBinding(Registration.DataBinding);
|
||||
Update();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void CopyDataBinding()
|
||||
@@ -282,7 +282,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
Update();
|
||||
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@
|
||||
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding"
|
||||
xmlns:modifierTypes="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding.ModifierTypes"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
@@ -16,7 +17,7 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.xaml" />
|
||||
<ResourceDictionary>
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
+5
-5
@@ -71,19 +71,19 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
public void Delete()
|
||||
{
|
||||
Modifier.DirectDataBinding.RemoveModifier(Modifier);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void ParameterSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
Modifier.UpdateParameterDynamic(e.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void StaticInputViewModelOnValueUpdated(object sender, DataModelInputStaticEventArgs e)
|
||||
{
|
||||
Modifier.UpdateParameterStatic(e.Value);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
@@ -100,7 +100,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
else if (Modifier.ParameterType == ProfileRightSideType.Dynamic)
|
||||
{
|
||||
DisposeStaticInputViewModel();
|
||||
DynamicSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
DynamicSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.SelectedProfileConfiguration.Module);
|
||||
if (DynamicSelectionViewModel != null)
|
||||
{
|
||||
DynamicSelectionViewModel.DisplaySwitchButton = true;
|
||||
@@ -149,7 +149,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
return;
|
||||
|
||||
Modifier.UpdateModifierType(modifierTypeViewModel.ModifierType);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
+5
-4
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared;
|
||||
@@ -87,7 +88,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
private void Initialize()
|
||||
{
|
||||
DirectDataBinding.ModifiersUpdated += DirectDataBindingOnModifiersUpdated;
|
||||
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.SelectedProfileConfiguration.Module);
|
||||
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
|
||||
ModifierViewModels.CollectionChanged += ModifierViewModelsOnCollectionChanged;
|
||||
Update();
|
||||
@@ -106,7 +107,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
|
||||
DirectDataBinding.ApplyOrder();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
#region Target
|
||||
@@ -116,7 +117,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
DirectDataBinding.UpdateSource(e.DataModelPath);
|
||||
Update();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -126,7 +127,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
public void AddModifier()
|
||||
{
|
||||
DirectDataBinding.AddModifier(ProfileRightSideType.Dynamic);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void UpdateModifierViewModels()
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects
|
||||
{
|
||||
await Task.Delay(500);
|
||||
renderElement.AddLayerEffect(SelectedLayerEffectDescriptor);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
d:DataContext="{d:DesignInstance {x:Type layerProperties:LayerPropertiesViewModel}}"
|
||||
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True">
|
||||
<UserControl.Resources>
|
||||
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<Converters:NullToBooleanConverter x:Key="NullToBooleanConverter" />
|
||||
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||
<Style x:Key="SvStyle" TargetType="{x:Type ScrollViewer}">
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
PopulateProperties(ProfileEditorService.SelectedProfileElement);
|
||||
|
||||
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||
ProfileEditorService.SelectedProfileElementChanged += SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
||||
ProfileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
@@ -197,7 +197,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
ProfileEditorService.SelectedProfileElementChanged -= SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
ProfileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
|
||||
ProfileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
@@ -218,7 +218,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
EffectsViewModel.PopulateDescriptors();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
private void SelectedProfileEditorServiceOnSelectedProfileElementChanged(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
PopulateProperties(e.RenderProfileElement);
|
||||
}
|
||||
@@ -419,7 +419,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
MoveAfter(source, target);
|
||||
|
||||
ApplyCurrentEffectsOrder();
|
||||
ProfileEditorService.UpdateSelectedProfile();
|
||||
ProfileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
|
||||
private void MoveBefore(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target)
|
||||
|
||||
+2
-2
@@ -118,7 +118,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
foreach (TimelineEasingViewModel propertyTrackEasingViewModel in EasingViewModels.Where(vm => vm != easingViewModel))
|
||||
propertyTrackEasingViewModel.IsEasingModeSelected = false;
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -174,7 +174,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
LayerPropertyKeyframe.LayerProperty.RemoveKeyframe(LayerPropertyKeyframe);
|
||||
if (save)
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
+7
-7
@@ -103,7 +103,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
if (Segment != SegmentViewModelType.Main || SelectedProfileElement == null)
|
||||
return;
|
||||
SelectedProfileElement.Timeline.PlayMode = value ? TimelinePlayMode.Repeat : TimelinePlayMode.Once;
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
NotifyOfPropertyChange(nameof(RepeatSegment));
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||
ProfileEditorService.SelectedProfileElementChanged += SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
if (ProfileEditorService.SelectedProfileElement != null)
|
||||
ProfileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
protected override void OnClose()
|
||||
{
|
||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
ProfileEditorService.SelectedProfileElementChanged -= SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
if (SelectedProfileElement != null)
|
||||
SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
base.OnClose();
|
||||
@@ -263,7 +263,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
}
|
||||
|
||||
ShiftNextSegment(SegmentLength - oldSegmentLength);
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
Update();
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
else if (Segment == SegmentViewModelType.End)
|
||||
SelectedProfileElement.Timeline.EndSegmentLength = TimeSpan.FromSeconds(1);
|
||||
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
Update();
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
((IInputElement) sender).ReleaseMouseCapture();
|
||||
_draggingSegment = false;
|
||||
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void SegmentMouseMove(object sender, MouseEventArgs e)
|
||||
@@ -367,7 +367,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
private void SelectedProfileEditorServiceOnSelectedProfileElementChanged(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.PreviousRenderProfileElement != null)
|
||||
e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
Update();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
private void SelectedProfileEditorServiceOnSelectedProfileElementChanged(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.PreviousRenderProfileElement != null)
|
||||
e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
@@ -100,7 +100,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementChanged += SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
if (_profileEditorService.SelectedProfileElement != null)
|
||||
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
|
||||
Update();
|
||||
@@ -111,7 +111,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementChanged -= SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
if (_profileEditorService.SelectedProfileElement != null)
|
||||
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
base.OnClose();
|
||||
@@ -142,7 +142,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
public void KeyframeMouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
ReleaseSelectedKeyframes();
|
||||
|
||||
((IInputElement) sender).ReleaseMouseCapture();
|
||||
@@ -200,7 +200,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
foreach (ITimelineKeyframeViewModel keyframeViewModel in keyframeViewModels)
|
||||
keyframeViewModel.Delete(false);
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void DuplicateKeyframes(object sender)
|
||||
@@ -213,7 +213,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
foreach (ITimelineKeyframeViewModel timelineKeyframeViewModel in GetAllKeyframeViewModels())
|
||||
timelineKeyframeViewModel.IsSelected = newKeyframes.Contains(timelineKeyframeViewModel.Keyframe);
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void CopyKeyframes()
|
||||
@@ -230,7 +230,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
foreach (ITimelineKeyframeViewModel timelineKeyframeViewModel in GetAllKeyframeViewModels())
|
||||
timelineKeyframeViewModel.IsSelected = newKeyframes.Contains(timelineKeyframeViewModel.Keyframe);
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private TimeSpan GetPastePosition(ITimelineKeyframeViewModel viewModel)
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
d:DataContext="{d:DesignInstance local:TreeGroupViewModel}"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<converters:PropertyTreeMarginConverter Length="20" x:Key="PropertyTreeMarginConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
_windowManager.ShowDialog(_layerBrushSettingsWindowVm);
|
||||
|
||||
// Save changes after the dialog closes
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
_windowManager.ShowDialog(_layerEffectSettingsWindowVm);
|
||||
|
||||
// Save changes after the dialog closes
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
{
|
||||
LayerPropertyGroup.LayerEffect.Name = newName;
|
||||
LayerPropertyGroup.LayerEffect.HasBeenRenamed = true;
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,12 +142,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
return;
|
||||
|
||||
LayerPropertyGroup.ProfileElement.RemoveLayerEffect(LayerPropertyGroup.LayerEffect);
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
|
||||
public void SuspendedToggled()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
|
||||
public double GetDepth()
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
public void ResetToDefault()
|
||||
{
|
||||
LayerProperty.ApplyDefaultValue();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void ApplyKeyframesEnabled(bool enable)
|
||||
@@ -67,7 +67,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
|
||||
LayerProperty.KeyframesEnabled = enable;
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
public bool HasDataBinding => LayerProperty.HasDataBinding;
|
||||
|
||||
@@ -21,30 +21,6 @@
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<DataTemplate x:Key="SimpleTemplate">
|
||||
<StackPanel d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}" Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="ExtendedTemplate">
|
||||
<Grid d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action DeleteProfile}"
|
||||
CommandParameter="{Binding}">
|
||||
<materialDesign:PackIcon Kind="Delete" Height="16" Width="16" HorizontalAlignment="Right" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -53,7 +29,7 @@
|
||||
<KeyBinding Command="{s:Action Redo}" Modifiers="Control" Key="Y" />
|
||||
</UserControl.InputBindings>
|
||||
|
||||
<Grid Margin="16">
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<!-- Left side -->
|
||||
<ColumnDefinition Width="*" MinWidth="100" />
|
||||
@@ -66,8 +42,6 @@
|
||||
<!-- Left side -->
|
||||
<Grid Grid.Row="0" Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<!-- Introduction -->
|
||||
<RowDefinition Height="35" />
|
||||
<!-- Design area -->
|
||||
<RowDefinition Height="*" MinHeight="200" />
|
||||
<!-- Bottom panels resize -->
|
||||
@@ -75,25 +49,17 @@
|
||||
<!-- Bottom panels -->
|
||||
<RowDefinition Height="{Binding BottomPanelsHeight.Value, Mode=TwoWay}" MinHeight="108" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Introduction -->
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock>
|
||||
<materialDesign:PackIcon Kind="AboutOutline" /> 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}" Margin="0 -2.5 0 0" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<!-- Design area -->
|
||||
<materialDesign:Card Grid.Row="1" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<materialDesign:Card Grid.Row="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ProfileViewModel, IsAsync=True}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- Bottom panels resize -->
|
||||
<GridSplitter Grid.Row="2" Grid.Column="0" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
<GridSplitter Grid.Row="1" Grid.Column="0" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
|
||||
<!-- Bottom panels -->
|
||||
<Grid Grid.Row="3">
|
||||
<Grid Grid.Row="2">
|
||||
<!-- Layer elements -->
|
||||
<materialDesign:Card Grid.Column="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding LayerPropertiesViewModel, IsAsync=True}" />
|
||||
@@ -102,105 +68,29 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Side panels resize -->
|
||||
<GridSplitter Grid.Row="0" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Cursor="SizeWE" Margin="5 35 5 0" />
|
||||
<GridSplitter Grid.Row="0" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Cursor="SizeWE" Margin="5 0" />
|
||||
|
||||
<!-- Side panels -->
|
||||
<Grid Grid.Row="0" Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<!-- Profile selection -->
|
||||
<RowDefinition Height="35" />
|
||||
<!-- Profile elements -->
|
||||
<!-- Profile elements -->
|
||||
<RowDefinition Height="*" MinHeight="100" />
|
||||
<!-- Conditions resize -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Display conditions -->
|
||||
<RowDefinition Height="{Binding DataModelConditionsHeight.Value, Mode=TwoWay}" MinHeight="100" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Profile selection -->
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox Height="26"
|
||||
VerticalAlignment="Top"
|
||||
ItemsSource="{Binding Profiles}"
|
||||
SelectedItem="{Binding SelectedProfile}"
|
||||
ItemTemplateSelector="{dataTemplateSelectors:ComboBoxTemplateSelector
|
||||
SelectedItemTemplate={StaticResource SimpleTemplate},
|
||||
DropdownItemsTemplate={StaticResource ExtendedTemplate}}">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
</ComboBox>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Add a new profile"
|
||||
Margin="5 0 0 0"
|
||||
Grid.Column="1"
|
||||
Width="26"
|
||||
Height="26"
|
||||
VerticalAlignment="Top"
|
||||
Command="{s:Action AddProfile}">
|
||||
<materialDesign:PackIcon Kind="Add" Height="20" Width="20" />
|
||||
</Button>
|
||||
<materialDesign:PopupBox Grid.Column="2" Margin="0 -10 0 0" PlacementMode="BottomAndAlignRightEdges">
|
||||
<StackPanel>
|
||||
<Button Command="{s:Action RenameActiveProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="RenameBox" Margin="0 0 15 0" />
|
||||
<TextBlock>Rename profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action DuplicateActiveProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="ContentDuplicate" Margin="0 0 15 0" />
|
||||
<TextBlock>Duplicate profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action DeleteActiveProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Trash" Margin="0 0 15 0" />
|
||||
<TextBlock>Delete profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Separator />
|
||||
|
||||
<Button Command="{s:Action AdaptActiveProfile}" ToolTip="Adapt the profile to the current surface">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="AutoFix" Margin="0 0 15 0" />
|
||||
<TextBlock>Adapt profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ExportActiveProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Upload" Margin="0 0 15 0" />
|
||||
<TextBlock>Export profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ImportProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Download" Margin="0 0 15 0" />
|
||||
<TextBlock>Import profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</Grid>
|
||||
|
||||
|
||||
<!-- Profile elements -->
|
||||
<materialDesign:Card Grid.Row="1" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<materialDesign:Card Grid.Row="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding ProfileTreeViewModel, IsAsync=True}" Margin="0,-1,-0.2,1" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- Conditions resize -->
|
||||
<GridSplitter Grid.Row="2" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />
|
||||
|
||||
<!-- Display conditions -->
|
||||
<materialDesign:Card Grid.Row="3" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<materialDesign:Card Grid.Row="2" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
|
||||
<ContentControl s:View.Model="{Binding DisplayConditionsViewModel, IsAsync=True}" />
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Dialogs;
|
||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
||||
@@ -18,9 +14,8 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor
|
||||
{
|
||||
public class ProfileEditorViewModel : Screen
|
||||
public class ProfileEditorViewModel : Screen, IMainScreenViewModel
|
||||
{
|
||||
private readonly IModuleService _moduleService;
|
||||
private readonly IMessageService _messageService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IProfileService _profileService;
|
||||
@@ -30,14 +25,11 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
private DisplayConditionsViewModel _displayConditionsViewModel;
|
||||
private PluginSetting<GridLength> _elementPropertiesWidth;
|
||||
private LayerPropertiesViewModel _layerPropertiesViewModel;
|
||||
private BindableCollection<ProfileDescriptor> _profiles;
|
||||
private ProfileTreeViewModel _profileTreeViewModel;
|
||||
private ProfileViewModel _profileViewModel;
|
||||
private ProfileDescriptor _selectedProfile;
|
||||
private PluginSetting<GridLength> _sidePanelsWidth;
|
||||
|
||||
public ProfileEditorViewModel(ProfileModule module,
|
||||
ProfileViewModel profileViewModel,
|
||||
public ProfileEditorViewModel(ProfileViewModel profileViewModel,
|
||||
ProfileTreeViewModel profileTreeViewModel,
|
||||
DisplayConditionsViewModel dataModelConditionsViewModel,
|
||||
LayerPropertiesViewModel layerPropertiesViewModel,
|
||||
@@ -45,21 +37,16 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
IProfileService profileService,
|
||||
IDialogService dialogService,
|
||||
ISettingsService settingsService,
|
||||
IModuleService moduleService,
|
||||
IMessageService messageService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_profileService = profileService;
|
||||
_settingsService = settingsService;
|
||||
_moduleService = moduleService;
|
||||
_messageService = messageService;
|
||||
|
||||
DisplayName = "PROFILE EDITOR";
|
||||
Module = module;
|
||||
DisplayName = "Profile Editor";
|
||||
DialogService = dialogService;
|
||||
|
||||
Profiles = new BindableCollection<ProfileDescriptor>();
|
||||
|
||||
// Populate the panels
|
||||
ProfileViewModel = profileViewModel;
|
||||
ProfileViewModel.ConductWith(this);
|
||||
@@ -71,7 +58,6 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
LayerPropertiesViewModel.ConductWith(this);
|
||||
}
|
||||
|
||||
public ProfileModule Module { get; }
|
||||
public IDialogService DialogService { get; }
|
||||
|
||||
public DisplayConditionsViewModel DisplayConditionsViewModel
|
||||
@@ -98,12 +84,6 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
set => SetAndNotify(ref _profileViewModel, value);
|
||||
}
|
||||
|
||||
public BindableCollection<ProfileDescriptor> Profiles
|
||||
{
|
||||
get => _profiles;
|
||||
set => SetAndNotify(ref _profiles, value);
|
||||
}
|
||||
|
||||
public PluginSetting<GridLength> SidePanelsWidth
|
||||
{
|
||||
get => _sidePanelsWidth;
|
||||
@@ -128,89 +108,9 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
set => SetAndNotify(ref _elementPropertiesWidth, value);
|
||||
}
|
||||
|
||||
public ProfileDescriptor SelectedProfile
|
||||
{
|
||||
get => _selectedProfile;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedProfile, value)) return;
|
||||
NotifyOfPropertyChange(nameof(CanDeleteActiveProfile));
|
||||
ActivateSelectedProfile();
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
|
||||
|
||||
public ProfileDescriptor CreateProfile(string name)
|
||||
{
|
||||
ProfileDescriptor profile = _profileService.CreateProfileDescriptor(Module, name);
|
||||
Profiles.Add(profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
public async Task AddProfile()
|
||||
{
|
||||
object result = await DialogService.ShowDialog<ProfileCreateViewModel>();
|
||||
if (result is string name)
|
||||
{
|
||||
ProfileDescriptor newProfile = CreateProfile(name);
|
||||
SelectedProfile = newProfile;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteProfile(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
bool result = await DialogService.ShowConfirmDialog(
|
||||
"Delete profile",
|
||||
$"Are you sure you want to delete '{profileDescriptor.Name}'? This cannot be undone."
|
||||
);
|
||||
|
||||
if (result)
|
||||
RemoveProfile(profileDescriptor);
|
||||
}
|
||||
|
||||
public async Task DeleteActiveProfile()
|
||||
{
|
||||
bool result = await DialogService.ShowConfirmDialog(
|
||||
"Delete active profile",
|
||||
"Are you sure you want to delete your currently active profile? This cannot be undone."
|
||||
);
|
||||
|
||||
if (result)
|
||||
RemoveProfile(SelectedProfile);
|
||||
}
|
||||
|
||||
public async Task RenameActiveProfile()
|
||||
{
|
||||
if (_profileEditorService.SelectedProfile == null)
|
||||
return;
|
||||
|
||||
Profile profile = _profileEditorService.SelectedProfile;
|
||||
object result = await DialogService.ShowDialog<ProfileEditViewModel>(new Dictionary<string, object> {{"profile", profile}});
|
||||
if (result is string name)
|
||||
{
|
||||
profile.Name = name;
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
|
||||
// The descriptors are immutable and need to be reloaded to reflect the name change
|
||||
LoadProfiles();
|
||||
SelectedProfile = Profiles.FirstOrDefault(p => p.Id == _profileEditorService.SelectedProfile.EntityId) ?? Profiles.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void DuplicateActiveProfile()
|
||||
{
|
||||
string encoded = _profileService.ExportProfile(SelectedProfile);
|
||||
ProfileDescriptor copy = _profileService.ImportProfile(encoded, Module, "copy");
|
||||
|
||||
Profiles.Add(copy);
|
||||
Profiles.Sort(p => p.Name);
|
||||
SelectedProfile = copy;
|
||||
}
|
||||
|
||||
public async Task AdaptActiveProfile()
|
||||
{
|
||||
if (_profileEditorService.SelectedProfile == null)
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Profile == null)
|
||||
return;
|
||||
|
||||
if (!await DialogService.ShowConfirmDialog(
|
||||
@@ -219,30 +119,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
))
|
||||
return;
|
||||
|
||||
_profileService.AdaptProfile(_profileEditorService.SelectedProfile);
|
||||
}
|
||||
|
||||
public async Task ExportActiveProfile()
|
||||
{
|
||||
await DialogService.ShowDialog<ProfileExportViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"profileDescriptor", SelectedProfile}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task ImportProfile()
|
||||
{
|
||||
object result = await DialogService.ShowDialog<ProfileImportViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"profileModule", Module}
|
||||
});
|
||||
|
||||
if (result != null && result is ProfileDescriptor descriptor)
|
||||
{
|
||||
Profiles.Add(descriptor);
|
||||
Profiles.Sort(p => p.Name);
|
||||
SelectedProfile = descriptor;
|
||||
}
|
||||
_profileService.AdaptProfile(_profileEditorService.SelectedProfileConfiguration.Profile);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
@@ -253,7 +130,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
// Store the focused element so we can restore it later
|
||||
IInputElement focusedElement = FocusManager.GetFocusedElement(Window.GetWindow(View));
|
||||
|
||||
if (!_profileEditorService.UndoUpdateProfile())
|
||||
if (!_profileEditorService.UndoSaveProfile())
|
||||
{
|
||||
_messageService.ShowMessage("Nothing to undo");
|
||||
return;
|
||||
@@ -280,7 +157,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
// Store the focused element so we can restore it later
|
||||
IInputElement focusedElement = FocusManager.GetFocusedElement(Window.GetWindow(View));
|
||||
|
||||
if (!_profileEditorService.RedoUpdateProfile())
|
||||
if (!_profileEditorService.RedoSaveProfile())
|
||||
{
|
||||
_messageService.ShowMessage("Nothing to redo");
|
||||
return;
|
||||
@@ -302,71 +179,17 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
LoadWorkspaceSettings();
|
||||
Module.IsProfileUpdatingDisabled = true;
|
||||
Module.ActiveProfile?.Reset();
|
||||
Module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
|
||||
LoadProfiles();
|
||||
|
||||
// If the module already has an active profile use that, the override won't trigger a profile change
|
||||
if (Module.ActiveProfile != null)
|
||||
SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId);
|
||||
|
||||
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(Module); });
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
SaveWorkspaceSettings();
|
||||
Module.IsProfileUpdatingDisabled = false;
|
||||
Module.ActiveProfile?.Reset();
|
||||
Module.ActiveProfileChanged -= ModuleOnActiveProfileChanged;
|
||||
_profileEditorService.ChangeSelectedProfileConfiguration(null);
|
||||
|
||||
_profileEditorService.ChangeSelectedProfile(null);
|
||||
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(null); });
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
private void RemoveProfile(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
if (SelectedProfile == profileDescriptor && !CanDeleteActiveProfile)
|
||||
return;
|
||||
|
||||
int index = Profiles.IndexOf(profileDescriptor);
|
||||
|
||||
// Get a new active profile
|
||||
ProfileDescriptor newActiveProfile = index - 1 > -1 ? Profiles[index - 1] : Profiles[index + 1];
|
||||
|
||||
// Activate the new active profile
|
||||
SelectedProfile = newActiveProfile;
|
||||
|
||||
// Remove the old one
|
||||
Profiles.Remove(profileDescriptor);
|
||||
_profileService.DeleteProfile(profileDescriptor);
|
||||
}
|
||||
|
||||
private void ActivateSelectedProfile()
|
||||
{
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
Task<Profile> changeTask = _profileService.ActivateProfileAnimated(SelectedProfile);
|
||||
_profileEditorService.ChangeSelectedProfile(null);
|
||||
Profile profile = await changeTask;
|
||||
_profileEditorService.ChangeSelectedProfile(profile);
|
||||
});
|
||||
}
|
||||
|
||||
private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Module.ActiveProfile == null)
|
||||
SelectedProfile = null;
|
||||
else
|
||||
SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId);
|
||||
}
|
||||
|
||||
private void LoadWorkspaceSettings()
|
||||
{
|
||||
SidePanelsWidth = _settingsService.GetSetting("ProfileEditor.SidePanelsWidth", new GridLength(385));
|
||||
@@ -382,12 +205,5 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
BottomPanelsHeight.Save();
|
||||
ElementPropertiesWidth.Save();
|
||||
}
|
||||
|
||||
private void LoadProfiles()
|
||||
{
|
||||
// Get all profiles from the database
|
||||
Profiles.Clear();
|
||||
Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(p => p.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -96,7 +96,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,13 +59,13 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
{
|
||||
_updatingTree = true;
|
||||
ProfileElement firstChild = _profileEditorService.SelectedProfile?.Children?.FirstOrDefault();
|
||||
if (!(firstChild is Folder folder))
|
||||
if (firstChild is not Folder folder)
|
||||
{
|
||||
ActivateItem(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateItem(_profileTreeVmFactory.FolderViewModel(folder));
|
||||
|
||||
ActiveItem = _profileTreeVmFactory.FolderViewModel(folder);
|
||||
_updatingTree = false;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
}
|
||||
|
||||
Unsubscribe();
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
Subscribe();
|
||||
}
|
||||
|
||||
@@ -177,17 +177,17 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
|
||||
private void Subscribe()
|
||||
{
|
||||
_profileEditorService.ProfileSelected += OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileChanged += OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged;
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
{
|
||||
_profileEditorService.ProfileSelected -= OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileChanged -= OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged -= OnSelectedProfileElementChanged;
|
||||
}
|
||||
|
||||
private void OnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
private void OnSelectedProfileElementChanged(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.RenderProfileElement == SelectedTreeItem?.ProfileElement)
|
||||
return;
|
||||
@@ -213,7 +213,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProfileSelected(object sender, EventArgs e)
|
||||
private void OnSelectedProfileChanged(object sender, EventArgs e)
|
||||
{
|
||||
CreateRootFolderViewModel();
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
throw new ArtemisUIException("Cannot add a folder to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
Folder _ = new(ProfileElement, "New folder");
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
|
||||
public void AddLayer()
|
||||
@@ -145,7 +145,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
layer.ChangeLayerBrush(brush);
|
||||
|
||||
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
_profileEditorService.ChangeSelectedProfileElement(layer);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
if (result is string newName)
|
||||
{
|
||||
ProfileElement.Name = newName;
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
ProfileElement.Parent?.RemoveChild(ProfileElement);
|
||||
parent.RemoveExistingElement(this);
|
||||
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
_profileEditorService.ChangeSelectedProfileElement(newSelection as RenderProfileElement);
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
|
||||
public void SuspendedToggled()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
_profileEditorService.SaveSelectedProfileConfiguration();
|
||||
}
|
||||
|
||||
public void ContextMenuOpening(object sender, EventArgs e)
|
||||
|
||||
@@ -178,8 +178,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
{
|
||||
Update();
|
||||
Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated;
|
||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved += OnSelectedProfileElementSaved;
|
||||
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
|
||||
_panZoomViewModel.PropertyChanged += PanZoomViewModelOnPropertyChanged;
|
||||
base.OnInitialActivate();
|
||||
@@ -189,8 +189,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
protected override void OnClose()
|
||||
{
|
||||
Layer.RenderPropertiesUpdated -= LayerOnRenderPropertiesUpdated;
|
||||
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.SelectedProfileElementChanged -= OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved -= OnSelectedProfileElementSaved;
|
||||
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
|
||||
_panZoomViewModel.PropertyChanged -= PanZoomViewModelOnPropertyChanged;
|
||||
base.OnClose();
|
||||
@@ -205,12 +205,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
Update();
|
||||
}
|
||||
|
||||
private void OnProfileElementSelected(object sender, EventArgs e)
|
||||
private void OnSelectedProfileElementChanged(object sender, EventArgs e)
|
||||
{
|
||||
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
||||
}
|
||||
|
||||
private void OnSelectedProfileElementUpdated(object sender, EventArgs e)
|
||||
private void OnSelectedProfileElementSaved(object sender, EventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
FocusSelectedLayer.SettingChanged += HighlightSelectedLayerOnSettingChanged;
|
||||
_rgbService.DeviceAdded += RgbServiceOnDevicesModified;
|
||||
_rgbService.DeviceRemoved += RgbServiceOnDevicesModified;
|
||||
_profileEditorService.ProfileSelected += OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.SelectedProfileChanged += OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved += OnSelectedProfileElementSaved;
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
@@ -166,9 +166,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
FocusSelectedLayer.SettingChanged -= HighlightSelectedLayerOnSettingChanged;
|
||||
_rgbService.DeviceAdded -= RgbServiceOnDevicesModified;
|
||||
_rgbService.DeviceRemoved -= RgbServiceOnDevicesModified;
|
||||
_profileEditorService.ProfileSelected -= OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.SelectedProfileChanged -= OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged -= OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved -= OnSelectedProfileElementSaved;
|
||||
if (_previousSelectedLayer != null)
|
||||
_previousSelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
|
||||
|
||||
@@ -330,12 +330,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
UpdateLedsDimStatus();
|
||||
}
|
||||
|
||||
private void OnProfileSelected(object sender, EventArgs e)
|
||||
private void OnSelectedProfileChanged(object sender, EventArgs e)
|
||||
{
|
||||
ApplyActiveProfile();
|
||||
}
|
||||
|
||||
private void OnProfileElementSelected(object sender, EventArgs e)
|
||||
private void OnSelectedProfileElementChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_previousSelectedLayer != null)
|
||||
{
|
||||
@@ -370,7 +370,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
ActivateToolByIndex(1);
|
||||
}
|
||||
|
||||
private void OnSelectedProfileElementUpdated(object sender, EventArgs e)
|
||||
private void OnSelectedProfileElementSaved(object sender, EventArgs e)
|
||||
{
|
||||
ApplyActiveProfile();
|
||||
UpdateLedsDimStatus();
|
||||
|
||||
@@ -75,9 +75,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
ProfileEditorService.ProfileSelected += UpdateEventHandler;
|
||||
ProfileEditorService.ProfileElementSelected += UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementUpdated += UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileChanged += UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementChanged += UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementSaved += UpdateEventHandler;
|
||||
ProfileEditorService.ProfilePreviewUpdated += UpdateEventHandler;
|
||||
|
||||
Update();
|
||||
@@ -92,9 +92,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
ProfileEditorService.ProfileSelected -= UpdateEventHandler;
|
||||
ProfileEditorService.ProfileElementSelected -= UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementUpdated -= UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileChanged -= UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementChanged -= UpdateEventHandler;
|
||||
ProfileEditorService.SelectedProfileElementSaved -= UpdateEventHandler;
|
||||
ProfileEditorService.ProfilePreviewUpdated -= UpdateEventHandler;
|
||||
base.OnClose();
|
||||
}
|
||||
@@ -117,7 +117,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
public void RotateMouseUp(object sender, ShapeControlEventArgs e)
|
||||
{
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
_rotating = false;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
public void ResizeMouseUp(object sender, ShapeControlEventArgs e)
|
||||
{
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
_isResizing = false;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
public void MoveMouseUp(object sender, ShapeControlEventArgs e)
|
||||
{
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
_movingShape = false;
|
||||
_movingAnchor = false;
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
layer.ClearLeds();
|
||||
layer.AddLeds(remainingLeds);
|
||||
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
layer.AddLeds(selectedLeds);
|
||||
}
|
||||
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
// If no layer selected, apply it to a new layer in the selected folder
|
||||
else if (ProfileEditorService.SelectedProfileElement is Folder folder)
|
||||
@@ -94,7 +94,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
newLayer.AddLeds(selectedLeds);
|
||||
ProfileEditorService.ChangeSelectedProfileElement(newLayer);
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
ProfileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,7 @@
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:screens="clr-namespace:Artemis.UI.Screens"
|
||||
xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:localization="clr-namespace:MaterialDesignExtensions.Localization;assembly=MaterialDesignExtensions"
|
||||
mc:Ignorable="d"
|
||||
FadeContentIfInactive="False"
|
||||
Icon="/Resources/Images/Logo/bow.ico"
|
||||
@@ -25,97 +23,58 @@
|
||||
KeyUp="{s:Action WindowKeyUp}"
|
||||
MouseDown="{s:Action WindowMouseDown}"
|
||||
MouseUp="{s:Action WindowMouseUp}"
|
||||
d:DesignHeight="640" d:DesignWidth="1200" d:DataContext="{d:DesignInstance screens:RootViewModel}">
|
||||
<mde:MaterialWindow.Resources>
|
||||
<Style TargetType="ContentControl" x:Key="InitializingFade">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ActiveItemReady}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.4">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseInOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
</mde:MaterialWindow.Resources>
|
||||
<materialDesign:DialogHost IsTabStop="False"
|
||||
Focusable="False"
|
||||
Identifier="RootDialog"
|
||||
DialogTheme="Inherit"
|
||||
SnackbarMessageQueue="{Binding MainMessageQueue}">
|
||||
d:DesignHeight="640" d:DesignWidth="1200"
|
||||
d:DataContext="{d:DesignInstance screens:RootViewModel}">
|
||||
<materialDesign:DialogHost IsTabStop="False" Focusable="False" Identifier="RootDialog" DialogTheme="Inherit" SnackbarMessageQueue="{Binding MainMessageQueue}">
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Left" DockPanel.ZIndex="2" ClipToBounds="True" Background="{DynamicResource MaterialDesignToolBarBackground}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl Grid.Column="0" s:View.Model="{Binding SidebarViewModel}" Width="240" />
|
||||
<Rectangle Grid.Column="1" Fill="DarkGray" Width="1" Margin="0 0 -1 0">
|
||||
<Rectangle.Effect>
|
||||
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="{StaticResource MaterialDesignShadow}" />
|
||||
</Rectangle.Effect>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding DockedSidebarViewModel.IsSidebarOpen}">
|
||||
<materialDesign:DrawerHost.LeftDrawerContent>
|
||||
<ContentControl s:View.Model="{Binding DockedSidebarViewModel}"
|
||||
Width="280"
|
||||
Visibility="{Binding PinSidebar.Value, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"/>
|
||||
</materialDesign:DrawerHost.LeftDrawerContent>
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Left"
|
||||
DockPanel.ZIndex="2"
|
||||
ClipToBounds="True"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
Visibility="{Binding PinSidebar.Value, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl Grid.Column="0" s:View.Model="{Binding PinnedSidebarViewModel}" Width="280" />
|
||||
<Rectangle Grid.Column="1" Fill="DarkGray" Width="1" Margin="0 0 -1 0">
|
||||
<Rectangle.Effect>
|
||||
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="{StaticResource MaterialDesignShadow}"/>
|
||||
</Rectangle.Effect>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<mde:AppBar Type="Dense"
|
||||
IsNavigationDrawerOpen="{Binding DockedSidebarViewModel.IsSidebarOpen, Mode=TwoWay}"
|
||||
Title="{Binding ActiveItem.DisplayName}"
|
||||
ShowNavigationDrawerButton="{Binding PinSidebar.Value, Converter={StaticResource InverseBooleanConverter}}"
|
||||
DockPanel.Dock="Top"
|
||||
DockPanel.ZIndex="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding FrameTime}"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Margin="10 0"
|
||||
ToolTip="The time the last frame took to render" />
|
||||
<materialDesign:ColorZone Mode="PrimaryMid" DockPanel.Dock="Top" DockPanel.ZIndex="1" Height="42">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding SidebarViewModel.SelectedScreen.DisplayName}"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="20"
|
||||
Margin="15 0" />
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding FrameTime}" VerticalAlignment="Center" FontSize="14" Margin="10 0" ToolTip="The time the last frame took to render" />
|
||||
|
||||
<!-- Bug: materialDesign:RippleAssist.RippleOnTop doesn't look as nice but otherwise it doesn't work at all, not sure why -->
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="Open debugger"
|
||||
Command="{s:Action ShowDebugger}"
|
||||
materialDesign:RippleAssist.RippleOnTop="True">
|
||||
<materialDesign:PackIcon Kind="Matrix" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</mde:AppBar>
|
||||
|
||||
<Grid>
|
||||
<ContentControl s:View.Model="{Binding ActiveItem}" Style="{StaticResource InitializingFade}" />
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar"
|
||||
MessageQueue="{Binding MainMessageQueue}"
|
||||
materialDesign:SnackbarMessage.InlineActionButtonMaxHeight="80"
|
||||
materialDesign:SnackbarMessage.ContentMaxHeight="200" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:DrawerHost>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<Grid>
|
||||
<ContentControl s:View.Model="{Binding SidebarViewModel.SelectedScreen}" />
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar"
|
||||
MessageQueue="{Binding MainMessageQueue}"
|
||||
materialDesign:SnackbarMessage.InlineActionButtonMaxHeight="80"
|
||||
materialDesign:SnackbarMessage.ContentMaxHeight="200" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:DialogHost>
|
||||
</mde:MaterialWindow>
|
||||
@@ -8,8 +8,6 @@ using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Screens.Modules;
|
||||
using Artemis.UI.Screens.Settings.Tabs.General;
|
||||
using Artemis.UI.Screens.Sidebar;
|
||||
using Artemis.UI.Screens.StartupWizard;
|
||||
using Artemis.UI.Services;
|
||||
@@ -23,20 +21,18 @@ using Constants = Artemis.Core.Constants;
|
||||
|
||||
namespace Artemis.UI.Screens
|
||||
{
|
||||
public sealed class RootViewModel : Conductor<IScreen>, IDisposable
|
||||
public sealed class RootViewModel : Conductor<Screen>, IDisposable
|
||||
{
|
||||
private readonly IRegistrationService _builtInRegistrationService;
|
||||
private readonly IMessageService _messageService;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private readonly IDebugService _debugService;
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly Timer _frameTimeUpdateTimer;
|
||||
private readonly SidebarViewModel _sidebarViewModel;
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IMessageService _messageService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private readonly PluginSetting<WindowSize> _windowSize;
|
||||
private bool _activeItemReady;
|
||||
private string _frameTime;
|
||||
private bool _lostFocus;
|
||||
private ISnackbarMessageQueue _mainMessageQueue;
|
||||
@@ -62,38 +58,24 @@ namespace Artemis.UI.Screens
|
||||
_debugService = debugService;
|
||||
_builtInRegistrationService = builtInRegistrationService;
|
||||
_messageService = messageService;
|
||||
_sidebarViewModel = sidebarViewModel;
|
||||
_frameTimeUpdateTimer = new Timer(500);
|
||||
|
||||
_windowSize = _settingsService.GetSetting<WindowSize>("UI.RootWindowSize");
|
||||
_sidebarViewModel.ConductWith(this);
|
||||
|
||||
ActiveItem = sidebarViewModel.SelectedItem;
|
||||
ActiveItemReady = true;
|
||||
PinSidebar = _settingsService.GetSetting("UI.PinSidebar", false);
|
||||
SidebarViewModel = sidebarViewModel;
|
||||
SidebarViewModel.ConductWith(this);
|
||||
|
||||
AssemblyInformationalVersionAttribute versionAttribute = typeof(RootViewModel).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
WindowTitle = $"Artemis {versionAttribute?.InformationalVersion} build {Constants.BuildInfo.BuildNumberDisplay}";
|
||||
}
|
||||
|
||||
public PluginSetting<bool> PinSidebar { get; }
|
||||
|
||||
// Just a litte trick to get the non-active variant completely removed from XAML (that should probably be done in the view)
|
||||
public SidebarViewModel PinnedSidebarViewModel => PinSidebar.Value ? _sidebarViewModel : null;
|
||||
public SidebarViewModel DockedSidebarViewModel => PinSidebar.Value ? null : _sidebarViewModel;
|
||||
public SidebarViewModel SidebarViewModel { get; }
|
||||
|
||||
public ISnackbarMessageQueue MainMessageQueue
|
||||
{
|
||||
get => _mainMessageQueue;
|
||||
set => SetAndNotify(ref _mainMessageQueue, value);
|
||||
}
|
||||
|
||||
public bool ActiveItemReady
|
||||
{
|
||||
get => _activeItemReady;
|
||||
set => SetAndNotify(ref _activeItemReady, value);
|
||||
}
|
||||
|
||||
|
||||
public string WindowTitle
|
||||
{
|
||||
get => _windowTitle;
|
||||
@@ -150,52 +132,15 @@ namespace Artemis.UI.Screens
|
||||
_eventAggregator.Publish(new MainWindowMouseEvent(sender, false, e));
|
||||
}
|
||||
|
||||
private void UpdateSidebarPinState()
|
||||
{
|
||||
_sidebarViewModel.IsSidebarOpen = true;
|
||||
|
||||
NotifyOfPropertyChange(nameof(PinnedSidebarViewModel));
|
||||
NotifyOfPropertyChange(nameof(DockedSidebarViewModel));
|
||||
}
|
||||
|
||||
private void UpdateFrameTime()
|
||||
{
|
||||
FrameTime = $"Frame time: {_coreService.FrameTime.TotalMilliseconds:F2} ms";
|
||||
}
|
||||
|
||||
private void SidebarViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(_sidebarViewModel.SelectedItem) && ActiveItem != _sidebarViewModel.SelectedItem)
|
||||
{
|
||||
// Unless the sidebar is pinned, close it upon selecting an item
|
||||
if (!PinSidebar.Value)
|
||||
_sidebarViewModel.IsSidebarOpen = false;
|
||||
|
||||
ActiveItemReady = false;
|
||||
|
||||
// Allow the menu to close, it's slower but feels more responsive, funny how that works right
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
await Task.Delay(400);
|
||||
ActiveItem = _sidebarViewModel.SelectedItem;
|
||||
await Task.Delay(200);
|
||||
ActiveItemReady = true;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFrameTimeUpdateTimerOnElapsed(object sender, ElapsedEventArgs args)
|
||||
{
|
||||
UpdateFrameTime();
|
||||
}
|
||||
|
||||
private void PinSidebarOnSettingChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSidebarPinState();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
@@ -203,7 +148,15 @@ namespace Artemis.UI.Screens
|
||||
_frameTimeUpdateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
private void SidebarViewModelOnSelectedScreenChanged(object? sender, EventArgs e)
|
||||
{
|
||||
ActiveItem = SidebarViewModel.SelectedScreen;
|
||||
}
|
||||
|
||||
private void ShowSetupWizard()
|
||||
{
|
||||
_windowManager.ShowDialog(_kernel.Get<StartupWizardViewModel>());
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
@@ -228,14 +181,14 @@ namespace Artemis.UI.Screens
|
||||
MainMessageQueue = _messageService.MainMessageQueue;
|
||||
UpdateFrameTime();
|
||||
|
||||
SidebarViewModel.SelectedScreenChanged += SidebarViewModelOnSelectedScreenChanged;
|
||||
ActiveItem = SidebarViewModel.SelectedScreen;
|
||||
|
||||
_builtInRegistrationService.RegisterBuiltInDataModelDisplays();
|
||||
_builtInRegistrationService.RegisterBuiltInDataModelInputs();
|
||||
_builtInRegistrationService.RegisterBuiltInPropertyEditors();
|
||||
|
||||
_frameTimeUpdateTimer.Elapsed += OnFrameTimeUpdateTimerOnElapsed;
|
||||
_sidebarViewModel.PropertyChanged += SidebarViewModelOnPropertyChanged;
|
||||
PinSidebar.SettingChanged += PinSidebarOnSettingChanged;
|
||||
|
||||
_frameTimeUpdateTimer.Start();
|
||||
|
||||
_window = (MaterialWindow) View;
|
||||
@@ -247,11 +200,6 @@ namespace Artemis.UI.Screens
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
private void ShowSetupWizard()
|
||||
{
|
||||
_windowManager.ShowDialog(_kernel.Get<StartupWizardViewModel>());
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
// Ensure no element with focus can leak, if we don't do this the root VM is retained by Window.EffectiveValues
|
||||
@@ -261,15 +209,13 @@ namespace Artemis.UI.Screens
|
||||
MainMessageQueue = null;
|
||||
_frameTimeUpdateTimer.Stop();
|
||||
|
||||
SidebarViewModel.SelectedScreenChanged -= SidebarViewModelOnSelectedScreenChanged;
|
||||
|
||||
_windowSize.Value ??= new WindowSize();
|
||||
_windowSize.Value.ApplyFromWindow(_window);
|
||||
_windowSize.Save();
|
||||
|
||||
_frameTimeUpdateTimer.Elapsed -= OnFrameTimeUpdateTimerOnElapsed;
|
||||
_sidebarViewModel.PropertyChanged -= SidebarViewModelOnPropertyChanged;
|
||||
PinSidebar.SettingChanged -= PinSidebarOnSettingChanged;
|
||||
|
||||
_sidebarViewModel.Dispose();
|
||||
|
||||
// Lets force the GC to run after closing the window so it is obvious to users watching task manager
|
||||
// that closing the UI will decrease the memory footprint of the application.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
using Artemis.Core;
|
||||
@@ -116,7 +117,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
|
||||
private void OnPluginFeatureToggled(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature is DataModelPluginFeature)
|
||||
if (e.PluginFeature is Module)
|
||||
PopulateModules();
|
||||
}
|
||||
|
||||
@@ -134,7 +135,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
private void GetDataModel()
|
||||
{
|
||||
MainDataModel = SelectedModule != null
|
||||
? _dataModelUIService.GetPluginDataModelVisualization(SelectedModule, false)
|
||||
? _dataModelUIService.GetPluginDataModelVisualization(new List<Module>() {SelectedModule}, false)
|
||||
: _dataModelUIService.GetMainDataModelVisualization();
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
_coreService.ModuleRenderingDisabled = true;
|
||||
_coreService.ProfileRenderingDisabled = true;
|
||||
await Task.Delay(100);
|
||||
|
||||
Device.X = X;
|
||||
@@ -200,7 +200,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
|
||||
_rgbService.SaveDevice(Device);
|
||||
|
||||
_coreService.ModuleRenderingDisabled = false;
|
||||
_coreService.ProfileRenderingDisabled = false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Artemis.UI.Screens.Settings.Tabs.About;
|
||||
using Artemis.UI.Screens.Settings.Tabs.Devices;
|
||||
using Artemis.UI.Screens.Settings.Tabs.General;
|
||||
using Artemis.UI.Screens.Settings.Tabs.Modules;
|
||||
using Artemis.UI.Screens.Settings.Tabs.Plugins;
|
||||
using Stylet;
|
||||
|
||||
@@ -11,7 +10,6 @@ namespace Artemis.UI.Screens.Settings
|
||||
{
|
||||
public SettingsViewModel(
|
||||
GeneralSettingsTabViewModel generalSettingsTabViewModel,
|
||||
ModuleOrderTabViewModel moduleOrderTabViewModel,
|
||||
PluginSettingsTabViewModel pluginSettingsTabViewModel,
|
||||
DeviceSettingsTabViewModel deviceSettingsTabViewModel,
|
||||
AboutTabViewModel aboutTabViewModel)
|
||||
@@ -19,7 +17,6 @@ namespace Artemis.UI.Screens.Settings
|
||||
DisplayName = "Settings";
|
||||
|
||||
Items.Add(generalSettingsTabViewModel);
|
||||
Items.Add(moduleOrderTabViewModel);
|
||||
Items.Add(pluginSettingsTabViewModel);
|
||||
Items.Add(deviceSettingsTabViewModel);
|
||||
Items.Add(aboutTabViewModel);
|
||||
|
||||
@@ -11,406 +11,426 @@
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:AboutTabViewModel}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="15" MaxWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image Grid.Column="0" Source="{svgc:SvgImage Source=/Resources/Images/Logo/bow.svg}" Width="60" Height="80" Margin="0 0 20 0" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Style="{StaticResource MaterialDesignHeadline2TextBlock}">
|
||||
Artemis 2
|
||||
</TextBlock>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="15" MaxWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image Grid.Column="0" Source="{svgc:SvgImage Source=/Resources/Images/Logo/bow.svg}" Width="60" Height="80" Margin="0 0 20 0" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Style="{StaticResource MaterialDesignHeadline2TextBlock}">
|
||||
Artemis 2
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View website"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://artemis-rgb.com">
|
||||
<materialDesign:PackIcon Kind="Web" />
|
||||
</Button>
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub repository"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/Artemis-RGB/Artemis">
|
||||
<materialDesign:PackIcon Kind="Github" />
|
||||
</Button>
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View Wiki"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com"
|
||||
Margin="0 0 -10 0">
|
||||
<materialDesign:PackIcon Kind="BookOpenOutline" />
|
||||
</Button>
|
||||
<StackPanel Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View website"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://artemis-rgb.com">
|
||||
<materialDesign:PackIcon Kind="Web" />
|
||||
</Button>
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub repository"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/Artemis-RGB/Artemis">
|
||||
<materialDesign:PackIcon Kind="Github" />
|
||||
</Button>
|
||||
<Button
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View Wiki"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com"
|
||||
Margin="0 0 -10 0">
|
||||
<materialDesign:PackIcon Kind="BookOpenOutline" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
Text="{Binding Version}" />
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}" RequestNavigate="{s:Action OpenHyperlink}" NavigateUri="https://github.com/Artemis-RGB/Artemis/blob/master/LICENSE">
|
||||
PolyForm Noncommercial License 1.0.0
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<materialDesign:Card Margin="0 25 0 0">
|
||||
<StackPanel Margin="15">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/8858506" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Robert 'Spoinky' Beekman
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Project owner, main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/SpoinkyNL/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/1094841" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Darth Affe
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/DarthAffe/RGB.NET">
|
||||
RGB.NET
|
||||
</Hyperlink>
|
||||
developer, main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/DarthAffe/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/29486064" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Diogo 'DrMeteor' Trindade
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/diogotr7/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://i.imgur.com/8mPWY1j.png" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Kai Werling
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Graphics design
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View website"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://kwer.online/">
|
||||
<materialDesign:PackIcon Kind="Web" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="AccountHeart" Width="30" Height="30" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="5 3 0 0">
|
||||
Special thanks
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" LineHeight="25" Margin="10 0 0 0">
|
||||
- The various people creating PRs to Artemis.Plugins and the main repository<LineBreak />
|
||||
- All the people on Discord providing feedback and testing
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0 20 0 0">
|
||||
<materialDesign:PackIcon Kind="LibraryShelves" Width="30" Height="30" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="5 3 0 0">
|
||||
External libraries
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" LineHeight="25" Margin="10 0 0 0">
|
||||
- Ben.Demystifier
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/benaadams/Ben.Demystifier">
|
||||
https://github.com/benaadams/Ben.Demystifier
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- EmbedIO
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://unosquare.github.io/embedio/">
|
||||
https://unosquare.github.io/embedio/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- FluentValidation
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://fluentvalidation.net/">
|
||||
https://fluentvalidation.net/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Furl.Http
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://flurl.dev//">
|
||||
https://flurl.dev/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- gong-wpf-dragdrop
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/punker76/gong-wpf-dragdrop">
|
||||
https://github.com/punker76/gong-wpf-dragdrop
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Hardcodet.NotifyIcon.Wpf.NetCore
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/HavenDV/H.NotifyIcon.WPF">
|
||||
https://github.com/HavenDV/H.NotifyIcon.WPF
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Humanizer
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/Humanizr/Humanizer">
|
||||
https://github.com/Humanizr/Humanizer
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- LiteDB
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://www.litedb.org/">
|
||||
https://www.litedb.org/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- MaterialDesignThemes
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit">
|
||||
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- MaterialDesignExtensions
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://spiegelp.github.io/MaterialDesignExtensions/">
|
||||
https://spiegelp.github.io/MaterialDesignExtensions/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- McMaster.NETCore.Plugins
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/natemcmaster/DotNetCorePlugins">
|
||||
https://github.com/natemcmaster/DotNetCorePlugins
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Newtonsoft.Json
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://www.newtonsoft.com/json">
|
||||
https://www.newtonsoft.com/json
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Ninject
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="http://www.ninject.org/">
|
||||
http://www.ninject.org/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Ookii.Dialogs.Wpf
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/ookii-dialogs/ookii-dialogs-wpf">
|
||||
https://github.com/ookii-dialogs/ookii-dialogs-wpf
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- RawInput.Sharp
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/mfakane/rawinput-sharp">
|
||||
https://github.com/mfakane/rawinput-sharp
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- RGB.NET
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/DarthAffe/RGB.NET">
|
||||
https://github.com/DarthAffe/RGB.NET
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Serilog
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://serilog.net/">
|
||||
https://serilog.net/
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- SkiaSharp
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/mono/SkiaSharp/">
|
||||
https://github.com/mono/SkiaSharp
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Stylet
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/canton7/Stylet">
|
||||
https://github.com/canton7/Stylet
|
||||
</Hyperlink>
|
||||
<LineBreak />
|
||||
- Unclassified.NetRevisionTask
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://unclassified.software/en/apps/netrevisiontask">
|
||||
https://unclassified.software/en/apps/netrevisiontask
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
Text="{Binding Version}" />
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}" RequestNavigate="{s:Action OpenHyperlink}" NavigateUri="https://github.com/Artemis-RGB/Artemis/blob/master/LICENSE">
|
||||
PolyForm Noncommercial License 1.0.0
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<materialDesign:Card Margin="0 25 0 0">
|
||||
<StackPanel Margin="15">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/8858506" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Robert 'Spoinky' Beekman
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Project owner, main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/SpoinkyNL/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/1094841" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Darth Affe
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/DarthAffe/RGB.NET">
|
||||
RGB.NET
|
||||
</Hyperlink> developer, main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/DarthAffe/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://avatars.githubusercontent.com/u/29486064" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Diogo 'DrMeteor' Trindade
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Main contributor
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View GitHub profile"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/diogotr7/">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Height="75"
|
||||
Width="75"
|
||||
Margin="0 0 15 0"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush ImageSource="https://i.imgur.com/8mPWY1j.png" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Padding="0">
|
||||
Kai Werling
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
Padding="0">
|
||||
Graphics design
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="-10">
|
||||
<Button Height="40"
|
||||
Width="40"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="View website"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://kwer.online/">
|
||||
<materialDesign:PackIcon Kind="Web" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="AccountHeart" Width="30" Height="30" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="5 3 0 0">
|
||||
Special thanks
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" LineHeight="25" Margin="10 0 0 0">
|
||||
- The various people creating PRs to Artemis.Plugins and the main repository<LineBreak />
|
||||
- All the people on Discord providing feedback and testing
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0 20 0 0">
|
||||
<materialDesign:PackIcon Kind="LibraryShelves" Width="30" Height="30" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="5 3 0 0">
|
||||
External libraries
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" LineHeight="25" Margin="10 0 0 0">
|
||||
- Ben.Demystifier
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/benaadams/Ben.Demystifier">
|
||||
https://github.com/benaadams/Ben.Demystifier
|
||||
</Hyperlink><LineBreak />
|
||||
- EmbedIO
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://unosquare.github.io/embedio/">
|
||||
https://unosquare.github.io/embedio/
|
||||
</Hyperlink><LineBreak />
|
||||
- FluentValidation
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://fluentvalidation.net/">
|
||||
https://fluentvalidation.net/
|
||||
</Hyperlink><LineBreak />
|
||||
- Furl.Http
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://flurl.dev//">
|
||||
https://flurl.dev/
|
||||
</Hyperlink><LineBreak />
|
||||
- gong-wpf-dragdrop
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/punker76/gong-wpf-dragdrop">
|
||||
https://github.com/punker76/gong-wpf-dragdrop
|
||||
</Hyperlink><LineBreak />
|
||||
- Hardcodet.NotifyIcon.Wpf.NetCore
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/HavenDV/H.NotifyIcon.WPF">
|
||||
https://github.com/HavenDV/H.NotifyIcon.WPF
|
||||
</Hyperlink><LineBreak />
|
||||
- Humanizer
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/Humanizr/Humanizer">
|
||||
https://github.com/Humanizr/Humanizer
|
||||
</Hyperlink><LineBreak />
|
||||
- LiteDB
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://www.litedb.org/">
|
||||
https://www.litedb.org/
|
||||
</Hyperlink><LineBreak />
|
||||
- MaterialDesignThemes
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit">
|
||||
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
|
||||
</Hyperlink><LineBreak />
|
||||
- MaterialDesignExtensions
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://spiegelp.github.io/MaterialDesignExtensions/">
|
||||
https://spiegelp.github.io/MaterialDesignExtensions/
|
||||
</Hyperlink><LineBreak />
|
||||
- McMaster.NETCore.Plugins
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/natemcmaster/DotNetCorePlugins">
|
||||
https://github.com/natemcmaster/DotNetCorePlugins
|
||||
</Hyperlink><LineBreak />
|
||||
- Newtonsoft.Json
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://www.newtonsoft.com/json">
|
||||
https://www.newtonsoft.com/json
|
||||
</Hyperlink><LineBreak />
|
||||
- Ninject
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="http://www.ninject.org/">
|
||||
http://www.ninject.org/
|
||||
</Hyperlink><LineBreak />
|
||||
- Ookii.Dialogs.Wpf
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/ookii-dialogs/ookii-dialogs-wpf">
|
||||
https://github.com/ookii-dialogs/ookii-dialogs-wpf
|
||||
</Hyperlink><LineBreak />
|
||||
- RawInput.Sharp
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/mfakane/rawinput-sharp">
|
||||
https://github.com/mfakane/rawinput-sharp
|
||||
</Hyperlink><LineBreak />
|
||||
- RGB.NET
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/DarthAffe/RGB.NET">
|
||||
https://github.com/DarthAffe/RGB.NET
|
||||
</Hyperlink><LineBreak />
|
||||
- Serilog
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://serilog.net/">
|
||||
https://serilog.net/
|
||||
</Hyperlink><LineBreak />
|
||||
- SkiaSharp
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/mono/SkiaSharp/">
|
||||
https://github.com/mono/SkiaSharp
|
||||
</Hyperlink><LineBreak />
|
||||
- Stylet
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://github.com/canton7/Stylet">
|
||||
https://github.com/canton7/Stylet
|
||||
</Hyperlink><LineBreak />
|
||||
- Unclassified.NetRevisionTask
|
||||
<Hyperlink Style="{StaticResource ArtemisHyperlink}"
|
||||
RequestNavigate="{s:Action OpenHyperlink}"
|
||||
NavigateUri="https://unclassified.software/en/apps/netrevisiontask">
|
||||
https://unclassified.software/en/apps/netrevisiontask
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,20 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Settings.Tabs.Modules.ModuleOrderModuleView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Modules"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:ModuleOrderModuleViewModel}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding Priority}"
|
||||
Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Module.DisplayName}" Style="{StaticResource MaterialDesignTextBlock}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using Artemis.Core.Modules;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings.Tabs.Modules
|
||||
{
|
||||
public class ModuleOrderModuleViewModel : PropertyChangedBase
|
||||
{
|
||||
private string _priority;
|
||||
|
||||
public ModuleOrderModuleViewModel(Module module)
|
||||
{
|
||||
Module = module;
|
||||
Update();
|
||||
}
|
||||
|
||||
public Module Module { get; }
|
||||
|
||||
public string Priority
|
||||
{
|
||||
get => _priority;
|
||||
set => SetAndNotify(ref _priority, value);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
switch (Module.PriorityCategory)
|
||||
{
|
||||
case ModulePriorityCategory.Normal:
|
||||
Priority = "3." + (Module.Priority + 1);
|
||||
break;
|
||||
case ModulePriorityCategory.Application:
|
||||
Priority = "2." + (Module.Priority + 1);
|
||||
break;
|
||||
case ModulePriorityCategory.Overlay:
|
||||
Priority = "1." + (Module.Priority + 1);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Settings.Tabs.Modules.ModuleOrderTabView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Modules"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:ModuleOrderTabViewModel}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<Grid Margin="15" MaxWidth="800">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15 0 0">Module priority</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap" Style="{StaticResource MaterialDesignTextBlock}">
|
||||
Drag and drop the modules below to change their rendering priority. <LineBreak /><LineBreak />
|
||||
- Like in the profile editor, the modules at the top render over modules at the bottom <LineBreak />
|
||||
- The categories serve as a starting point for new modules, you may freely move modules between the categories <LineBreak />
|
||||
</TextBlock>
|
||||
|
||||
<Grid Margin="0 0 0 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}">1 - Overlays</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="10 0">
|
||||
Modules that should always render on top
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||
<StackPanel Margin="15">
|
||||
<Border BorderThickness="2">
|
||||
<Border.BorderBrush>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Rectangle StrokeDashArray="4 2" Stroke="{DynamicResource MaterialDesignDivider}" StrokeThickness="2"
|
||||
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
|
||||
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Border.BorderBrush>
|
||||
<ListBox ItemsSource="{Binding OverlayModules}"
|
||||
materialDesign:RippleAssist.IsDisabled="True"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||
dd:DragDrop.DropHandler="{Binding}"
|
||||
MinHeight="40">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1">
|
||||
<Grid Margin="0 15 0 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}">2 - Applications/games</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="10 0">
|
||||
Modules that are related to specific applications or games
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||
<StackPanel Margin="15">
|
||||
<Border BorderThickness="2">
|
||||
<Border.BorderBrush>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Rectangle StrokeDashArray="4 2" Stroke="{DynamicResource MaterialDesignDivider}" StrokeThickness="2"
|
||||
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
|
||||
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Border.BorderBrush>
|
||||
<ListBox ItemsSource="{Binding ApplicationModules}"
|
||||
materialDesign:RippleAssist.IsDisabled="True"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||
dd:DragDrop.DropHandler="{Binding}"
|
||||
MinHeight="40">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2">
|
||||
<Grid Margin="0 15 0 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}">3 - Normal</TextBlock>
|
||||
<TextBlock Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="10 0">
|
||||
Regular modules that are always active in the background
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||
<StackPanel Margin="15">
|
||||
<Border BorderThickness="2">
|
||||
<Border.BorderBrush>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Rectangle StrokeDashArray="4 2" Stroke="{DynamicResource MaterialDesignDivider}" StrokeThickness="2"
|
||||
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
|
||||
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Border.BorderBrush>
|
||||
<ListBox ItemsSource="{Binding NormalModules}"
|
||||
materialDesign:RippleAssist.IsDisabled="True"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||
dd:DragDrop.DropHandler="{Binding}"
|
||||
MinHeight="40">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,97 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using GongSolutions.Wpf.DragDrop;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings.Tabs.Modules
|
||||
{
|
||||
public class ModuleOrderTabViewModel : Screen, IDropTarget
|
||||
{
|
||||
private readonly IModuleService _moduleService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly DefaultDropHandler _defaultDropHandler;
|
||||
private List<ModuleOrderModuleViewModel> _modules;
|
||||
|
||||
public ModuleOrderTabViewModel(IPluginManagementService pluginManagementService, IModuleService moduleService)
|
||||
{
|
||||
DisplayName = "MODULE PRIORITY";
|
||||
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_moduleService = moduleService;
|
||||
_defaultDropHandler = new DefaultDropHandler();
|
||||
|
||||
NormalModules = new BindableCollection<ModuleOrderModuleViewModel>();
|
||||
ApplicationModules = new BindableCollection<ModuleOrderModuleViewModel>();
|
||||
OverlayModules = new BindableCollection<ModuleOrderModuleViewModel>();
|
||||
}
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
base.OnActivate();
|
||||
Update();
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
base.OnDeactivate();
|
||||
_modules = null;
|
||||
}
|
||||
|
||||
public BindableCollection<ModuleOrderModuleViewModel> NormalModules { get; set; }
|
||||
public BindableCollection<ModuleOrderModuleViewModel> ApplicationModules { get; set; }
|
||||
public BindableCollection<ModuleOrderModuleViewModel> OverlayModules { get; set; }
|
||||
|
||||
public void DragOver(IDropInfo dropInfo)
|
||||
{
|
||||
_defaultDropHandler.DragOver(dropInfo);
|
||||
}
|
||||
|
||||
public void Drop(IDropInfo dropInfo)
|
||||
{
|
||||
if (dropInfo.TargetItem == dropInfo.Data)
|
||||
return;
|
||||
|
||||
if (!(dropInfo.Data is ModuleOrderModuleViewModel viewModel))
|
||||
return;
|
||||
if (!(dropInfo.TargetCollection is BindableCollection<ModuleOrderModuleViewModel> targetCollection))
|
||||
return;
|
||||
|
||||
int insertIndex = dropInfo.InsertIndex;
|
||||
|
||||
ModulePriorityCategory category;
|
||||
if (targetCollection == NormalModules)
|
||||
category = ModulePriorityCategory.Normal;
|
||||
else if (targetCollection == ApplicationModules)
|
||||
category = ModulePriorityCategory.Application;
|
||||
else
|
||||
category = ModulePriorityCategory.Overlay;
|
||||
|
||||
// If moving down, take the removal of ourselves into consideration with the insert index
|
||||
if (targetCollection.Contains(viewModel) && targetCollection.IndexOf(viewModel) < insertIndex)
|
||||
insertIndex--;
|
||||
|
||||
_moduleService.UpdateModulePriority(viewModel.Module, category, insertIndex);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (_modules == null)
|
||||
_modules = _pluginManagementService.GetFeaturesOfType<Module>().Select(m => new ModuleOrderModuleViewModel(m)).ToList();
|
||||
NormalModules.Clear();
|
||||
NormalModules.AddRange(_modules.Where(m => m.Module.PriorityCategory == ModulePriorityCategory.Normal).OrderBy(m => m.Module.Priority));
|
||||
|
||||
ApplicationModules.Clear();
|
||||
ApplicationModules.AddRange(_modules.Where(m => m.Module.PriorityCategory == ModulePriorityCategory.Application).OrderBy(m => m.Module.Priority));
|
||||
|
||||
OverlayModules.Clear();
|
||||
OverlayModules.AddRange(_modules.Where(m => m.Module.PriorityCategory == ModulePriorityCategory.Overlay).OrderBy(m => m.Module.Priority));
|
||||
|
||||
foreach (ModuleOrderModuleViewModel moduleOrderModuleViewModel in _modules)
|
||||
moduleOrderModuleViewModel.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="-3 -8">
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
|
||||
<Style x:Key="SidebarListBoxItem" TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource MaterialDesignToolToggleListBoxItem}">
|
||||
<Setter Property="Padding" Value="8" />
|
||||
<Setter Property="Margin" Value="6 1" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Margin="{TemplateBinding Margin}"
|
||||
ClipToBounds="{TemplateBinding ClipToBounds}"
|
||||
Cursor="Hand">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup Name="CommonStates">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition GeneratedDuration="0:0:0.3" To="Normal">
|
||||
<VisualTransition.GeneratedEasingFunction>
|
||||
<CircleEase EasingMode="EaseOut" />
|
||||
</VisualTransition.GeneratedEasingFunction>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState Name="Normal" />
|
||||
<VisualState Name="MouseOver">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="Opacity"
|
||||
To="0.03" Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup Name="SelectionStates">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition From="*" To="Selected">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedBackgroundBorder">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="*" To="SelectedUnfocused">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedBackgroundBorder">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="Selected" To="Unselected">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="SelectedBackgroundBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0" Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState Name="Selected">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="SelectedBackgroundBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1" Duration="0" />
|
||||
<DoubleAnimation Storyboard.TargetName="SelectedBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1" Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Unselected" />
|
||||
<VisualState Name="SelectedUnfocused">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="SelectedBackgroundBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1" Duration="0" />
|
||||
<DoubleAnimation Storyboard.TargetName="SelectedBorder"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1" Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Grid>
|
||||
<Grid.OpacityMask>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Border Background="Black"
|
||||
CornerRadius="4"
|
||||
Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}}"
|
||||
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Grid}}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Grid.OpacityMask>
|
||||
<Border x:Name="MouseOverBorder"
|
||||
Opacity="0"
|
||||
Background="{TemplateBinding Foreground, Converter={StaticResource BrushRoundConverter}}" />
|
||||
<Border x:Name="SelectedBackgroundBorder"
|
||||
Opacity="0"
|
||||
Background="{DynamicResource MaterialDesignDivider}" />
|
||||
<materialDesign:Ripple x:Name="Ripple" Feedback="{TemplateBinding Foreground, Converter={StaticResource BrushRoundConverter}}"
|
||||
Opacity=".82"
|
||||
Focusable="False"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Padding="{TemplateBinding Padding}" />
|
||||
<Border x:Name="SelectedBorder"
|
||||
Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=SelectionMode, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static SelectionMode.Extended}, Mode=OneWay}"
|
||||
Opacity="0"
|
||||
BorderThickness="0"
|
||||
BorderBrush="{DynamicResource MaterialDesignDivider}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="Ripple" Property="Opacity" Value=".92" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value=".56" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit.ModuleActivationRequirementView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:ModuleActivationRequirementViewModel}">
|
||||
<Border BorderThickness="0 1 0 0" BorderBrush="{DynamicResource MaterialDesignDivider}" Padding="10">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Text="{Binding RequirementName}" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding RequirementDescription}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}"
|
||||
Focusable="False"
|
||||
IsHitTestVisible="False"
|
||||
IsChecked="{Binding RequirementMet}">
|
||||
<ToggleButton.Content>
|
||||
<Border Background="#E74C4C" Width="32" Height="32">
|
||||
<materialDesign:PackIcon Kind="Close" VerticalAlignment="Center" HorizontalAlignment="Center" />
|
||||
</Border>
|
||||
</ToggleButton.Content>
|
||||
<materialDesign:ToggleButtonAssist.OnContent>
|
||||
<materialDesign:PackIcon Kind="Check" />
|
||||
</materialDesign:ToggleButtonAssist.OnContent>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</UserControl>
|
||||
+4
-4
@@ -4,16 +4,16 @@ using Artemis.Core.Modules;
|
||||
using Humanizer;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Modules.Tabs
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
||||
{
|
||||
public sealed class ActivationRequirementViewModel : Screen, IDisposable
|
||||
public sealed class ModuleActivationRequirementViewModel : Screen, IDisposable
|
||||
{
|
||||
private readonly IModuleActivationRequirement _activationRequirement;
|
||||
private readonly Timer _updateTimer;
|
||||
private string _requirementDescription;
|
||||
private bool _requirementMet;
|
||||
|
||||
public ActivationRequirementViewModel(IModuleActivationRequirement activationRequirement)
|
||||
public ModuleActivationRequirementViewModel(IModuleActivationRequirement activationRequirement)
|
||||
{
|
||||
_activationRequirement = activationRequirement;
|
||||
_updateTimer = new Timer(500);
|
||||
@@ -63,7 +63,7 @@ namespace Artemis.UI.Screens.Modules.Tabs
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit.ModuleActivationRequirementsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:ModuleActivationRequirementsViewModel}">
|
||||
<StackPanel>
|
||||
<TextBlock TextWrapping="Wrap" Style="{StaticResource MaterialDesignTextBlock}">
|
||||
This module has built-in activation requirements and your profile won't activate until
|
||||
<Run Text="{Binding ActivationType}" FontWeight="Medium" Foreground="{StaticResource SecondaryHueMidBrush}" />. <LineBreak />
|
||||
These requirements allow the module creator to decide when the data is available to your profile you cannot override them.
|
||||
</TextBlock>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding Items}" Margin="0 10 0 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
||||
{
|
||||
public class ModuleActivationRequirementsViewModel : Conductor<ModuleActivationRequirementViewModel>.Collection.AllActive
|
||||
{
|
||||
private readonly ISidebarVmFactory _sidebarVmFactory;
|
||||
private Module _module;
|
||||
private string _activationType;
|
||||
|
||||
public ModuleActivationRequirementsViewModel(ISidebarVmFactory sidebarVmFactory)
|
||||
{
|
||||
_sidebarVmFactory = sidebarVmFactory;
|
||||
}
|
||||
|
||||
public Module Module
|
||||
{
|
||||
get => _module;
|
||||
set => SetAndNotify(ref _module, value);
|
||||
}
|
||||
|
||||
public string ActivationType
|
||||
{
|
||||
get => _activationType;
|
||||
set => SetAndNotify(ref _activationType, value);
|
||||
}
|
||||
|
||||
public void SetModule(Module module)
|
||||
{
|
||||
Module = module;
|
||||
ActivationType = Module != null && Module.ActivationRequirementMode == ActivationRequirementType.All
|
||||
? "all requirements are met"
|
||||
: "any requirement is met";
|
||||
|
||||
Items.Clear();
|
||||
if (Module != null)
|
||||
Items.AddRange(Module.ActivationRequirements.Select(_sidebarVmFactory.ModuleActivationRequirementViewModel));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit.ProfileEditView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:profileEdit="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="280"
|
||||
d:DataContext="{d:DesignInstance {x:Type profileEdit:ProfileEditViewModel}}"
|
||||
Width="800">
|
||||
<UserControl.Resources>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
<shared:StreamToBitmapImageConverter x:Key="StreamToBitmapImageConverter"/>
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<shared:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignHeadline6TextBlock}"
|
||||
Margin="0 0 0 10"
|
||||
Visibility="{Binding IsNew, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
Add a new profile
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignHeadline6TextBlock}"
|
||||
Margin="0 0 0 10"
|
||||
Visibility="{Binding IsNew, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<Run Text="{Binding ProfileConfiguration.Name}" /> | Properties
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 0 0 14">
|
||||
General
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBox materialDesign:HintAssist.Hint="Profile name"
|
||||
Margin="0 4 0 8"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding ProfileName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<ComboBox materialDesign:HintAssist.Hint="Module"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
materialDesign:HintAssist.HelperText="Optional and binds the profile to the selected module, making module data available."
|
||||
Margin="0 0 0 32"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
SelectedItem="{Binding SelectedModule}">
|
||||
<ComboBox.ItemsSource>
|
||||
<CompositeCollection>
|
||||
<ComboBoxItem IsEnabled="False"
|
||||
Visibility="{Binding HasUsableModules, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
No usable modules found
|
||||
</ComboBoxItem>
|
||||
<CollectionContainer Collection="{Binding Data.Modules, Source={StaticResource DataContextProxy}}" />
|
||||
</CompositeCollection>
|
||||
</ComboBox.ItemsSource>
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type profileEdit:ProfileModuleViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<shared:ArtemisIcon Icon="{Binding Icon}" Width="16" Height="16" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox materialDesign:HintAssist.Hint="Icon type"
|
||||
Margin="0 0 0 8"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
SelectedValue="{Binding SelectedIconType}"
|
||||
ItemsSource="{Binding IconTypes}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description" />
|
||||
|
||||
<ContentControl VerticalAlignment="Center">
|
||||
<ContentControl.Style>
|
||||
<Style TargetType="ContentControl">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding SelectedIconType}" Value="{x:Static core:ProfileConfigurationIconType.MaterialIcon}">
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon Grid.Column="0"
|
||||
Kind="{Binding DataContext.SelectedIcon.Icon, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=OneWay}"
|
||||
Width="45"
|
||||
Height="45"
|
||||
Margin="0 0 10 0"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<ComboBox Grid.Column="1"
|
||||
materialDesign:HintAssist.Hint="Profile icon"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
SelectedItem="{Binding DataContext.SelectedIcon, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
IsEnabled="{Binding DataContext.Initializing, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource InverseBooleanConverter}}"
|
||||
ItemsSource="{Binding DataContext.Icons, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
TextSearch.TextPath="IconName">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type profileEdit:ProfileIconViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="{Binding Icon}" Width="16" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding IconName}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding SelectedIconType}" Value="{x:Static core:ProfileConfigurationIconType.BitmapImage}">
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image Grid.Column="0"
|
||||
Source="{Binding DataContext.SelectedImage, Converter={StaticResource StreamToBitmapImageConverter}, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Margin="0 0 10 0"
|
||||
Width="45"
|
||||
Height="45"
|
||||
VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1"
|
||||
Command="{s:Action SelectBitmapFile}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
ToolTip="Select an image">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Paperclip" Margin="0 0 10 0" />
|
||||
<TextBlock>BROWSE IMAGE</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding SelectedIconType}" Value="{x:Static core:ProfileConfigurationIconType.SvgImage}">
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<svgc:SvgViewbox Grid.Column="0"
|
||||
StreamSource="{Binding DataContext.SelectedImage, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
Margin="0 0 10 0"
|
||||
Width="45"
|
||||
Height="45"
|
||||
VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1"
|
||||
Command="{s:Action SelectSvgFile}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
ToolTip="Select an image">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Paperclip" Margin="0 0 10 0" />
|
||||
<TextBlock>BROWSE IMAGE</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ContentControl.Style>
|
||||
</ContentControl>
|
||||
</StackPanel>
|
||||
|
||||
<Border Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="{StaticResource MaterialDesignDivider}" Width="1" Margin="10 0" />
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
Keybinds
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}">You may set up keybinds to activate/deactivate the profile</TextBlock>
|
||||
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16">
|
||||
<materialDesign:PackIcon Kind="Crane" Width="100" Height="100" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 20">
|
||||
Keybinds are not yet implemented
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Margin="0 16" BorderThickness="1" Height="1" BorderBrush="{StaticResource MaterialDesignDivider}" />
|
||||
|
||||
<Grid Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
Activation conditions
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}">If you only want this profile to be active under certain conditions, configure those conditions below</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<materialDesign:Card Grid.Row="1" Background="{DynamicResource MaterialDesignToolBarBackground}" Padding="10">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
MinHeight="150"
|
||||
MaxHeight="300"
|
||||
Margin="0 5">
|
||||
<ContentControl s:View.Model="{Binding ActivationConditionViewModel}" />
|
||||
</ScrollViewer>
|
||||
</materialDesign:Card>
|
||||
|
||||
<Grid Grid.Row="2" Margin="0 10" Visibility="{Binding SelectedModule, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="0" BorderThickness="1" Height="1" BorderBrush="{StaticResource MaterialDesignDivider}" />
|
||||
<TextBlock Grid.Column="1" Margin="16 0" Style="{StaticResource MaterialDesignBody2TextBlock}">AND</TextBlock>
|
||||
<Border Grid.Column="2" BorderThickness="1" Height="1" BorderBrush="{StaticResource MaterialDesignDivider}" />
|
||||
</Grid>
|
||||
|
||||
<materialDesign:Card Grid.Row="3"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
Padding="10"
|
||||
Visibility="{Binding SelectedModule, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}">
|
||||
<ContentControl s:View.Model="{Binding ModuleActivationRequirementsViewModel}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" Margin="0 16 0 0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource MaterialDesignFlatAccentButton}"
|
||||
Command="{s:Action Delete}"
|
||||
Visibility="{Binding IsNew, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
DELETE
|
||||
</Button>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" Command="{s:Action Accept}">
|
||||
ACCEPT
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
||||
{
|
||||
public class ProfileEditViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly DataModelConditionGroup _dataModelConditionGroup;
|
||||
private readonly List<Module> _modules;
|
||||
private readonly IProfileService _profileService;
|
||||
private bool _changedImage;
|
||||
private bool _initializing;
|
||||
private string _profileName;
|
||||
private ProfileIconViewModel _selectedIcon;
|
||||
private ProfileConfigurationIconType _selectedIconType;
|
||||
private Stream _selectedImage;
|
||||
private ProfileModuleViewModel _selectedModule;
|
||||
|
||||
public ProfileEditViewModel(ProfileConfiguration profileConfiguration, bool isNew,
|
||||
IProfileService profileService,
|
||||
IPluginManagementService pluginManagementService,
|
||||
ISidebarVmFactory sidebarVmFactory,
|
||||
IDataModelConditionsVmFactory dataModelConditionsVmFactory,
|
||||
IModelValidator<ProfileEditViewModel> validator) : base(validator)
|
||||
{
|
||||
ProfileConfiguration = profileConfiguration;
|
||||
IsNew = isNew;
|
||||
|
||||
_profileService = profileService;
|
||||
_dataModelConditionGroup = ProfileConfiguration.ActivationCondition ?? new DataModelConditionGroup(null);
|
||||
_modules = ProfileConfiguration.Module != null ? new List<Module> {ProfileConfiguration.Module} : new List<Module>();
|
||||
|
||||
IconTypes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ProfileConfigurationIconType)));
|
||||
Icons = new BindableCollection<ProfileIconViewModel>();
|
||||
Modules = new BindableCollection<ProfileModuleViewModel>(
|
||||
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
||||
);
|
||||
Initializing = true;
|
||||
ActivationConditionViewModel = dataModelConditionsVmFactory.DataModelConditionGroupViewModel(_dataModelConditionGroup, ConditionGroupType.General, _modules);
|
||||
ActivationConditionViewModel.ConductWith(this);
|
||||
ActivationConditionViewModel.IsRootGroup = true;
|
||||
ModuleActivationRequirementsViewModel = new ModuleActivationRequirementsViewModel(sidebarVmFactory);
|
||||
ModuleActivationRequirementsViewModel.ConductWith(this);
|
||||
ModuleActivationRequirementsViewModel.SetModule(ProfileConfiguration.Module);
|
||||
|
||||
_profileName = ProfileConfiguration.Name;
|
||||
_selectedModule = Modules.FirstOrDefault(m => m.Module == ProfileConfiguration.Module);
|
||||
_selectedIconType = ProfileConfiguration.Icon.IconType;
|
||||
_selectedImage = ProfileConfiguration.Icon.FileIcon;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
Icons.AddRange(Enum.GetValues<PackIconKind>()
|
||||
.GroupBy(i => i).Select(g => g.First()).Select(i => new ProfileIconViewModel(i))
|
||||
.OrderBy(i => i.IconName)
|
||||
.ToList());
|
||||
if (IsNew)
|
||||
SelectedIcon = Icons[new Random().Next(0, Icons.Count - 1)];
|
||||
else
|
||||
SelectedIcon = Icons.FirstOrDefault(i => i.Icon.ToString() == ProfileConfiguration.Icon.MaterialIcon);
|
||||
Initializing = false;
|
||||
});
|
||||
}
|
||||
|
||||
public ProfileConfiguration ProfileConfiguration { get; }
|
||||
public bool IsNew { get; }
|
||||
public BindableCollection<ValueDescription> IconTypes { get; }
|
||||
public BindableCollection<ProfileIconViewModel> Icons { get; }
|
||||
public BindableCollection<ProfileModuleViewModel> Modules { get; }
|
||||
public bool HasUsableModules => Modules.Any();
|
||||
|
||||
public bool Initializing
|
||||
{
|
||||
get => _initializing;
|
||||
set => SetAndNotify(ref _initializing, value);
|
||||
}
|
||||
|
||||
public string ProfileName
|
||||
{
|
||||
get => _profileName;
|
||||
set => SetAndNotify(ref _profileName, value);
|
||||
}
|
||||
|
||||
public ProfileConfigurationIconType SelectedIconType
|
||||
{
|
||||
get => _selectedIconType;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedIconType, value)) return;
|
||||
SelectedImage = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream SelectedImage
|
||||
{
|
||||
get => _selectedImage;
|
||||
set => SetAndNotify(ref _selectedImage, value);
|
||||
}
|
||||
|
||||
public ProfileIconViewModel SelectedIcon
|
||||
{
|
||||
get => _selectedIcon;
|
||||
set => SetAndNotify(ref _selectedIcon, value);
|
||||
}
|
||||
|
||||
public ProfileModuleViewModel SelectedModule
|
||||
{
|
||||
get => _selectedModule;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedModule, value)) return;
|
||||
_modules.Clear();
|
||||
if (value != null)
|
||||
_modules.Add(value.Module);
|
||||
|
||||
ActivationConditionViewModel.UpdateModules();
|
||||
ModuleActivationRequirementsViewModel.SetModule(value?.Module);
|
||||
}
|
||||
}
|
||||
|
||||
public DataModelConditionGroupViewModel ActivationConditionViewModel { get; }
|
||||
public ModuleActivationRequirementsViewModel ModuleActivationRequirementsViewModel { get; }
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
Session.Close(nameof(Delete));
|
||||
}
|
||||
|
||||
public async Task Accept()
|
||||
{
|
||||
await ValidateAsync();
|
||||
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
ProfileConfiguration.Name = ProfileName;
|
||||
ProfileConfiguration.Icon.IconType = SelectedIconType;
|
||||
ProfileConfiguration.Icon.MaterialIcon = SelectedIcon?.Icon.ToString();
|
||||
ProfileConfiguration.Icon.FileIcon = SelectedImage;
|
||||
|
||||
ProfileConfiguration.Module = SelectedModule?.Module;
|
||||
|
||||
if (_dataModelConditionGroup.Children.Any())
|
||||
ProfileConfiguration.ActivationCondition = _dataModelConditionGroup;
|
||||
|
||||
if (_changedImage)
|
||||
{
|
||||
ProfileConfiguration.Icon.FileIcon = SelectedImage;
|
||||
_profileService.SaveProfileConfigurationIcon(ProfileConfiguration);
|
||||
}
|
||||
|
||||
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
||||
|
||||
Session.Close(nameof(Accept));
|
||||
}
|
||||
|
||||
public void SelectBitmapFile()
|
||||
{
|
||||
VistaOpenFileDialog dialog = new()
|
||||
{
|
||||
Filter = "All Graphics Types|*.bmp;*.jpg;*.jpeg;*.png;*.tif;*.tiff|BMP |*.bmp|GIF|*.gif|JPG|*.jpg;*.jpeg|PNG|*.png|TIFF|*.tif;*.tiff",
|
||||
Title = "Select profile icon"
|
||||
};
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result != true)
|
||||
return;
|
||||
|
||||
_changedImage = true;
|
||||
|
||||
// TODO: Scale down to 100x100-ish
|
||||
SelectedImage = File.OpenRead(dialog.FileName);
|
||||
}
|
||||
|
||||
public void SelectSvgFile()
|
||||
{
|
||||
VistaOpenFileDialog dialog = new()
|
||||
{
|
||||
Filter = "Scalable Vector Graphics|*.svg",
|
||||
Title = "Select profile icon"
|
||||
};
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result != true)
|
||||
return;
|
||||
|
||||
_changedImage = true;
|
||||
SelectedImage = File.OpenRead(dialog.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfileEditViewModelValidator : AbstractValidator<ProfileEditViewModel>
|
||||
{
|
||||
public ProfileEditViewModelValidator()
|
||||
{
|
||||
RuleFor(m => m.ProfileName).NotEmpty().WithMessage("Profile name may not be empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
||||
{
|
||||
public class ProfileIconViewModel
|
||||
{
|
||||
public ProfileIconViewModel(PackIconKind icon)
|
||||
{
|
||||
Icon = icon;
|
||||
IconName = icon.ToString();
|
||||
}
|
||||
|
||||
public PackIconKind Icon { get; }
|
||||
public string IconName { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Artemis.Core.Modules;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
||||
{
|
||||
public class ProfileModuleViewModel : PropertyChangedBase
|
||||
{
|
||||
public ProfileModuleViewModel(Module module)
|
||||
{
|
||||
Module = module;
|
||||
Icon = module.DisplayIcon;
|
||||
Name = module.DisplayName;
|
||||
Description = module.Info.Description;
|
||||
}
|
||||
|
||||
public string Icon { get; }
|
||||
public string Name { get; }
|
||||
public string Description { get; }
|
||||
|
||||
public Module Module { get; }
|
||||
}
|
||||
}
|
||||
+14
-14
@@ -1,30 +1,30 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Dialogs.ProfileEditView"
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.Dialogs.SidebarCategoryCreateView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="213.053" d:DesignWidth="254.425">
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="280"
|
||||
Width="300">
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
|
||||
Edit profile
|
||||
Add a new category
|
||||
</TextBlock>
|
||||
|
||||
<TextBox materialDesign:HintAssist.Hint="Profile name"
|
||||
Margin="0 8 0 16"
|
||||
Width="300"
|
||||
<TextBox materialDesign:HintAssist.Hint="Category name"
|
||||
Margin="0 16 0 8"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding ProfileName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
Text="{Binding CategoryName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 0 8 0" Command="{s:Action Cancel}">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 0 0 0" Command="{s:Action Accept}">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Command="{s:Action Accept}">
|
||||
ACCEPT
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Artemis.UI.Screens.ProfileEditor.Dialogs;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs
|
||||
{
|
||||
public class SidebarCategoryCreateViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly IProfileService _profileService;
|
||||
private string _categoryName;
|
||||
|
||||
public SidebarCategoryCreateViewModel(IProfileService profileService, IModelValidator<SidebarCategoryCreateViewModel> validator) : base(validator)
|
||||
{
|
||||
_profileService = profileService;
|
||||
}
|
||||
|
||||
public string CategoryName
|
||||
{
|
||||
get => _categoryName;
|
||||
set => SetAndNotify(ref _categoryName, value);
|
||||
}
|
||||
|
||||
public async Task Accept()
|
||||
{
|
||||
await ValidateAsync();
|
||||
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
Session.Close(_profileService.CreateProfileCategory(CategoryName));
|
||||
}
|
||||
}
|
||||
|
||||
public class SidebarCategoryCreateViewModelValidator : AbstractValidator<SidebarCategoryCreateViewModel>
|
||||
{
|
||||
private readonly IProfileCategoryRepository _profileCategoryRepository;
|
||||
|
||||
public SidebarCategoryCreateViewModelValidator(IProfileCategoryRepository profileCategoryRepository)
|
||||
{
|
||||
_profileCategoryRepository = profileCategoryRepository;
|
||||
|
||||
RuleFor(m => m.CategoryName)
|
||||
.NotEmpty().WithMessage("Category name may not be empty")
|
||||
.Must(BeUniqueCategory).WithMessage("Category name already taken");
|
||||
}
|
||||
|
||||
private bool BeUniqueCategory(SidebarCategoryCreateViewModel viewModel, string categoryName)
|
||||
{
|
||||
return _profileCategoryRepository.IsUnique(categoryName, null) == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.Dialogs.SidebarCategoryUpdateView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="280"
|
||||
Width="300">
|
||||
<StackPanel Margin="16" >
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
|
||||
Update category
|
||||
</TextBlock>
|
||||
|
||||
<TextBox materialDesign:HintAssist.Hint="Category name"
|
||||
Margin="0 16 0 8"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding CategoryName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<Grid Margin="0 8 0 0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource MaterialDesignFlatAccentButton}"
|
||||
Command="{s:Action Delete}">
|
||||
DELETE
|
||||
</Button>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Command="{s:Action Accept}">
|
||||
ACCEPT
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar.Dialogs
|
||||
{
|
||||
public class SidebarCategoryUpdateViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IProfileService _profileService;
|
||||
private string _categoryName;
|
||||
|
||||
public SidebarCategoryUpdateViewModel(ProfileCategory profileCategory, IProfileService profileService, IDialogService dialogService,
|
||||
IModelValidator<SidebarCategoryUpdateViewModel> validator) : base(validator)
|
||||
{
|
||||
_categoryName = profileCategory.Name;
|
||||
_profileService = profileService;
|
||||
_dialogService = dialogService;
|
||||
|
||||
ProfileCategory = profileCategory;
|
||||
}
|
||||
|
||||
public ProfileCategory ProfileCategory { get; }
|
||||
|
||||
public string CategoryName
|
||||
{
|
||||
get => _categoryName;
|
||||
set => SetAndNotify(ref _categoryName, value);
|
||||
}
|
||||
|
||||
public async Task Accept()
|
||||
{
|
||||
await ValidateAsync();
|
||||
|
||||
if (HasErrors)
|
||||
return;
|
||||
|
||||
ProfileCategory.Name = CategoryName;
|
||||
_profileService.SaveProfileCategory(ProfileCategory);
|
||||
|
||||
Session.Close(nameof(Accept));
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
Session.Close(nameof(Delete));
|
||||
}
|
||||
}
|
||||
|
||||
public class SidebarCategoryUpdateViewModelValidator : AbstractValidator<SidebarCategoryUpdateViewModel>
|
||||
{
|
||||
private readonly IProfileCategoryRepository _profileCategoryRepository;
|
||||
|
||||
public SidebarCategoryUpdateViewModelValidator(IProfileCategoryRepository profileCategoryRepository)
|
||||
{
|
||||
_profileCategoryRepository = profileCategoryRepository;
|
||||
|
||||
RuleFor(m => m.CategoryName)
|
||||
.NotEmpty().WithMessage("Category name may not be empty")
|
||||
.Must(BeUniqueCategory).WithMessage("Category name already taken");
|
||||
}
|
||||
|
||||
private bool BeUniqueCategory(SidebarCategoryUpdateViewModel viewModel, string categoryName)
|
||||
{
|
||||
return _profileCategoryRepository.IsUnique(categoryName, viewModel.ProfileCategory.EntityId) == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarCategoryView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:SidebarCategoryViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ArtemisSidebar.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0 8 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Background="Transparent">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToggleButton Grid.Column="0"
|
||||
x:Name="Expander"
|
||||
Foreground="{DynamicResource MaterialDesignBody}"
|
||||
Style="{StaticResource MaterialDesignExpandCollapseToggleStyle}"
|
||||
IsChecked="{Binding ShowItems}"
|
||||
ClickMode="Press"
|
||||
Margin="5 0" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Padding="0 5"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding ProfileCategory.Name}"
|
||||
MouseLeftButtonUp="{s:Action OnMouseLeftButtonUp}">
|
||||
<TextBlock.Style>
|
||||
<Style>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSuspended}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.33" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<Border Grid.Column="1" BorderThickness="1" BorderBrush="{DynamicResource MaterialDesignBody}" Height="1" Opacity="0">
|
||||
<Border.Style>
|
||||
<Style>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSuspended}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.75" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
ToolTip="Edit category"
|
||||
Width="26"
|
||||
Height="26"
|
||||
Command="{s:Action UpdateCategory}"
|
||||
HorizontalAlignment="Right">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignIconForegroundButton}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type Grid}, Mode=FindAncestor}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<materialDesign:PackIcon Kind="Cog" Width="16" Height="16" />
|
||||
</Button>
|
||||
<ToggleButton Grid.Column="3" ToolTip="Suspend profile" Width="18" Height="18" Margin="2 0 0 0" IsChecked="{Binding IsSuspended}">
|
||||
<ToggleButton.Style>
|
||||
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MaterialDesignFlatToggleButton}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type Grid}, Mode=FindAncestor}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
<materialDesign:PackIcon Kind="Pause" Height="14" Width="14" />
|
||||
</ToggleButton>
|
||||
|
||||
|
||||
<materialDesign:PopupBox Grid.Column="4"
|
||||
PlacementMode="BottomAndAlignCentres"
|
||||
ToolTip="Add profile"
|
||||
Margin="0 0 10 0">
|
||||
<materialDesign:PopupBox.Style>
|
||||
<Style TargetType="{x:Type materialDesign:PopupBox}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type Grid}, Mode=FindAncestor}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</materialDesign:PopupBox.Style>
|
||||
<materialDesign:PopupBox.ToggleContent>
|
||||
<materialDesign:PackIcon Kind="Plus" Width="20" Height="20" Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</materialDesign:PopupBox.ToggleContent>
|
||||
<StackPanel>
|
||||
<Button Command="{s:Action AddProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Plus" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock VerticalAlignment="Center"> Add new profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ImportProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Import" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock VerticalAlignment="Center">Import existing profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1">
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="ProfileDragTemplate" DataType="{x:Type local:SidebarProfileConfigurationViewModel}">
|
||||
<Border Background="{DynamicResource MaterialDesignDivider}" Padding="10" CornerRadius="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<shared:ProfileConfigurationIcon ConfigurationIcon="{Binding ProfileConfiguration.Icon}"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="0 0 10 0"
|
||||
Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
<TextBlock Text="{Binding ProfileConfiguration.Name}" VerticalAlignment="Center" Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<ListBox ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedProfileConfiguration}"
|
||||
MinHeight="10"
|
||||
PreviewMouseRightButtonDown="UIElement_OnPreviewMouseRightButtonDown"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.DropHandler="{Binding}"
|
||||
dd:DragDrop.DragAdornerTemplate="{StaticResource ProfileDragTemplate}">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Paste" Command="{s:Action Paste}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="ContentPaste" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource SidebarListBoxItem}" />
|
||||
</ListBox.ItemContainerStyle>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SidebarCategoryView.xaml
|
||||
/// </summary>
|
||||
public partial class SidebarCategoryView : UserControl
|
||||
{
|
||||
public SidebarCategoryView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void UIElement_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.Sidebar.Dialogs;
|
||||
using Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using GongSolutions.Wpf.DragDrop;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using MaterialDesignThemes.Wpf.Transitions;
|
||||
using Newtonsoft.Json;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
public class SidebarCategoryViewModel : Conductor<SidebarProfileConfigurationViewModel>.Collection.AllActive, IDropTarget
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly ISidebarVmFactory _vmFactory;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IProfileService _profileService;
|
||||
private SidebarProfileConfigurationViewModel _selectedProfileConfiguration;
|
||||
private bool _showItems;
|
||||
private readonly DefaultDropHandler _defaultDropHandler;
|
||||
private bool _addingProfile;
|
||||
|
||||
public SidebarCategoryViewModel(ProfileCategory profileCategory,
|
||||
IProfileService profileService,
|
||||
IDialogService dialogService,
|
||||
ISidebarVmFactory vmFactory,
|
||||
IEventAggregator eventAggregator)
|
||||
{
|
||||
_profileService = profileService;
|
||||
_dialogService = dialogService;
|
||||
_vmFactory = vmFactory;
|
||||
_eventAggregator = eventAggregator;
|
||||
_showItems = !profileCategory.IsCollapsed;
|
||||
_defaultDropHandler = new DefaultDropHandler();
|
||||
|
||||
ProfileCategory = profileCategory;
|
||||
}
|
||||
|
||||
public ProfileCategory ProfileCategory { get; }
|
||||
|
||||
public bool ShowItems
|
||||
{
|
||||
get => _showItems;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _showItems, value)) return;
|
||||
|
||||
if (value)
|
||||
CreateProfileViewModels();
|
||||
else
|
||||
Items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSuspended
|
||||
{
|
||||
get => ProfileCategory.IsSuspended;
|
||||
set
|
||||
{
|
||||
ProfileCategory.IsSuspended = value;
|
||||
NotifyOfPropertyChange(nameof(IsSuspended));
|
||||
_profileService.SaveProfileCategory(ProfileCategory);
|
||||
}
|
||||
}
|
||||
|
||||
public SidebarProfileConfigurationViewModel SelectedProfileConfiguration
|
||||
{
|
||||
get => _selectedProfileConfiguration;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedProfileConfiguration, value)) return;
|
||||
if (value == null) return;
|
||||
try
|
||||
{
|
||||
((SidebarViewModel) Parent).SelectProfileConfiguration(value.ProfileConfiguration);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_dialogService.ShowExceptionDialog("Failed select profile", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateCategory()
|
||||
{
|
||||
object result = await _dialogService.ShowDialog<SidebarCategoryUpdateViewModel>(new Dictionary<string, object> {{"profileCategory", ProfileCategory}});
|
||||
if (result is nameof(SidebarCategoryUpdateViewModel.Delete))
|
||||
await DeleteCategory();
|
||||
}
|
||||
|
||||
public async Task DeleteCategory()
|
||||
{
|
||||
bool confirmed = await _dialogService.ShowConfirmDialog(
|
||||
"Delete category",
|
||||
"Are you sure you want to delete this category?\r\nAll profiles will be deleted too."
|
||||
);
|
||||
if (!confirmed)
|
||||
return;
|
||||
|
||||
// Close the editor first by heading to Home if any of the profiles are being edited
|
||||
if (ProfileCategory.ProfileConfigurations.Any(p => p.IsBeingEdited))
|
||||
_eventAggregator.Publish(new RequestSelectSidebarItemEvent("Home"));
|
||||
|
||||
_profileService.DeleteProfileCategory(ProfileCategory);
|
||||
((SidebarViewModel) Parent).RemoveProfileCategoryViewModel(this);
|
||||
}
|
||||
|
||||
public void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ShowItems = !ShowItems;
|
||||
}
|
||||
|
||||
public async Task AddProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
_addingProfile = true;
|
||||
ProfileConfiguration profileConfiguration = _profileService.CreateProfileConfiguration(ProfileCategory, "New profile", Enum.GetValues<PackIconKind>().First().ToString());
|
||||
object result = await _dialogService.ShowDialog<ProfileEditViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"profileConfiguration", profileConfiguration},
|
||||
{"isNew", true}
|
||||
});
|
||||
if (result is nameof(ProfileEditViewModel.Accept))
|
||||
{
|
||||
if (!ShowItems)
|
||||
ShowItems = true;
|
||||
else
|
||||
CreateProfileViewModels();
|
||||
}
|
||||
else
|
||||
_profileService.RemoveProfileConfiguration(profileConfiguration);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_addingProfile = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ImportProfile()
|
||||
{
|
||||
VistaOpenFileDialog dialog = new()
|
||||
{
|
||||
Filter = "Artemis Profile|*.json",
|
||||
Title = "Export Artemis profile"
|
||||
};
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result != true)
|
||||
return;
|
||||
|
||||
string json = await File.ReadAllTextAsync(dialog.FileName);
|
||||
try
|
||||
{
|
||||
ProfileConfigurationExportModel profileConfigurationExportModel = JsonConvert.DeserializeObject<ProfileConfigurationExportModel>(json, IProfileService.ExportSettings);
|
||||
if (profileConfigurationExportModel == null)
|
||||
{
|
||||
await _dialogService.ShowConfirmDialog("Import profile", "Failed to import this profile, make sure it is a valid Artemis profile.", "Confirm", null);
|
||||
return;
|
||||
}
|
||||
|
||||
_profileService.ImportProfile(ProfileCategory, profileConfigurationExportModel);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _dialogService.ShowConfirmDialog("Import profile", $"Failed to import this profile, make sure it is a valid Artemis profile.\r\n{e.Message}", "Confirm", null);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateProfileViewModels()
|
||||
{
|
||||
Items.Clear();
|
||||
foreach (ProfileConfiguration profileConfiguration in ProfileCategory.ProfileConfigurations.OrderBy(p => p.Order))
|
||||
Items.Add(_vmFactory.SidebarProfileConfigurationViewModel(profileConfiguration));
|
||||
|
||||
SelectedProfileConfiguration = Items.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited);
|
||||
}
|
||||
|
||||
private void ProfileCategoryOnProfileConfigurationRemoved(object sender, ProfileConfigurationEventArgs e)
|
||||
{
|
||||
if (!_addingProfile && ShowItems)
|
||||
{
|
||||
Items.Remove(Items.FirstOrDefault(i => i.ProfileConfiguration == e.ProfileConfiguration));
|
||||
((BindableCollection<SidebarProfileConfigurationViewModel>) Items).Sort(p => p.ProfileConfiguration.Order);
|
||||
}
|
||||
|
||||
SelectedProfileConfiguration = Items.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited);
|
||||
}
|
||||
|
||||
private void ProfileCategoryOnProfileConfigurationAdded(object sender, ProfileConfigurationEventArgs e)
|
||||
{
|
||||
if (!_addingProfile && ShowItems)
|
||||
{
|
||||
Items.Add(_vmFactory.SidebarProfileConfigurationViewModel(e.ProfileConfiguration));
|
||||
((BindableCollection<SidebarProfileConfigurationViewModel>) Items).Sort(p => p.ProfileConfiguration.Order);
|
||||
}
|
||||
|
||||
SelectedProfileConfiguration = Items.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited);
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
#region Overrides of AllActive
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
CreateProfileViewModels();
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
ProfileCategory.ProfileConfigurationAdded += ProfileCategoryOnProfileConfigurationAdded;
|
||||
ProfileCategory.ProfileConfigurationRemoved += ProfileCategoryOnProfileConfigurationRemoved;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
ProfileCategory.ProfileConfigurationAdded -= ProfileCategoryOnProfileConfigurationAdded;
|
||||
ProfileCategory.ProfileConfigurationRemoved -= ProfileCategoryOnProfileConfigurationRemoved;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDropTarget
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DragOver(IDropInfo dropInfo)
|
||||
{
|
||||
_defaultDropHandler.DragOver(dropInfo);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Drop(IDropInfo dropInfo)
|
||||
{
|
||||
if (dropInfo.Data is not SidebarProfileConfigurationViewModel sourceItem)
|
||||
return;
|
||||
if (dropInfo.Data == dropInfo.TargetItem)
|
||||
return;
|
||||
|
||||
SidebarCategoryViewModel sourceCategory = (SidebarCategoryViewModel) sourceItem.Parent;
|
||||
SidebarCategoryViewModel targetCategory = (SidebarCategoryViewModel) ((FrameworkElement) dropInfo.VisualTarget).DataContext;
|
||||
|
||||
int targetIndex = 0;
|
||||
if (dropInfo.TargetItem is SidebarProfileConfigurationViewModel targetItem)
|
||||
{
|
||||
if (dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.BeforeTargetItem))
|
||||
targetIndex = targetCategory.Items.IndexOf(targetItem);
|
||||
else
|
||||
targetIndex = targetCategory.Items.IndexOf(targetItem) + 1;
|
||||
}
|
||||
|
||||
targetCategory.ProfileCategory.AddProfileConfiguration(sourceItem.ProfileConfiguration, targetIndex);
|
||||
|
||||
if (sourceCategory != targetCategory)
|
||||
_profileService.SaveProfileCategory(sourceCategory.ProfileCategory);
|
||||
_profileService.SaveProfileCategory(targetCategory.ProfileCategory);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.SidebarProfileConfigurationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:SidebarProfileConfigurationViewModel}"
|
||||
Background="Transparent"
|
||||
Margin="-8"
|
||||
Padding="8">
|
||||
<!-- Above is a dumb hack to get the context menu to cover the entire item -->
|
||||
<UserControl.Resources>
|
||||
<shared:StreamToBitmapImageConverter x:Key="StreamToBitmapImageConverter" />
|
||||
</UserControl.Resources>
|
||||
<UserControl.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="View properties" Command="{s:Action ViewProperties}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Cog" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Suspend" IsCheckable="True" IsChecked="{Binding IsSuspended}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Pause" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Suspend all">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Pause" />
|
||||
</MenuItem.Icon>
|
||||
<MenuItem Header="Above" Command="{s:Action SuspendAbove}" CommandParameter="suspend" />
|
||||
<MenuItem Header="Below" Command="{s:Action SuspendBelow}" CommandParameter="suspend" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="Resume all">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Play" />
|
||||
</MenuItem.Icon>
|
||||
<MenuItem Header="Above" Command="{s:Action SuspendAbove}" CommandParameter="resume" />
|
||||
<MenuItem Header="Below" Command="{s:Action SuspendBelow}" CommandParameter="resume" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Export" Command="{s:Action Export}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Export" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Duplicate" Command="{s:Action Duplicate}" >
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="ContentDuplicate" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Copy" Command="{s:Action Copy}" >
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="ContentCopy" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Paste" Command="{s:Action Paste}" >
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="ContentPaste" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Delete" Command="{s:Action Delete}" InputGestureText="Del">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="TrashCan" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</UserControl.ContextMenu>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<shared:ProfileConfigurationIcon Grid.Column="0" VerticalAlignment="Center" ConfigurationIcon="{Binding ProfileConfiguration.Icon}" Width="20" Height="20">
|
||||
<shared:ProfileConfigurationIcon.Style>
|
||||
<Style>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsProfileActive}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.33" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</shared:ProfileConfigurationIcon.Style>
|
||||
</shared:ProfileConfigurationIcon>
|
||||
|
||||
<TextBlock Grid.Column="1" FontSize="12" Margin="10 0 0 0" VerticalAlignment="Center" Text="{Binding ProfileConfiguration.Name}">
|
||||
<TextBlock.Style>
|
||||
<Style>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsProfileActive}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.33" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="{DynamicResource MaterialDesignBody}" Height="1" Opacity="0">
|
||||
<Border.Style>
|
||||
<Style>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSuspended}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.75" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
|
||||
<Button Grid.Column="2" ToolTip="View properties" Width="20" Height="20" Command="{s:Action ViewProperties}" HorizontalAlignment="Right">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignIconForegroundButton}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<materialDesign:PackIcon Kind="Cog" Width="16" Height="16" />
|
||||
</Button>
|
||||
<ToggleButton Grid.Column="3" ToolTip="Suspend profile" Width="18" Height="18" Margin="2 0 0 0" IsChecked="{Binding IsSuspended}">
|
||||
<ToggleButton.Style>
|
||||
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MaterialDesignFlatToggleButton}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
<materialDesign:PackIcon Kind="Pause" Height="14" Width="14" />
|
||||
</ToggleButton>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,165 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
public class SidebarProfileConfigurationViewModel : Screen
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IProfileService _profileService;
|
||||
|
||||
public SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration,
|
||||
IProfileService profileService,
|
||||
IDialogService dialogService,
|
||||
IEventAggregator eventAggregator)
|
||||
{
|
||||
_profileService = profileService;
|
||||
_dialogService = dialogService;
|
||||
_eventAggregator = eventAggregator;
|
||||
ProfileConfiguration = profileConfiguration;
|
||||
}
|
||||
|
||||
public ProfileConfiguration ProfileConfiguration { get; }
|
||||
|
||||
public bool IsProfileActive => ProfileConfiguration.Profile != null;
|
||||
|
||||
public bool IsSuspended
|
||||
{
|
||||
get => ProfileConfiguration.IsSuspended;
|
||||
set
|
||||
{
|
||||
ProfileConfiguration.IsSuspended = value;
|
||||
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ViewProperties()
|
||||
{
|
||||
object result = await _dialogService.ShowDialog<ProfileEditViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"profileConfiguration", ProfileConfiguration},
|
||||
{"isNew", false}
|
||||
});
|
||||
|
||||
if (result is nameof(ProfileEditViewModel.Delete))
|
||||
await Delete();
|
||||
}
|
||||
|
||||
public void SuspendAbove(string action)
|
||||
{
|
||||
foreach (ProfileConfiguration profileConfiguration in ProfileConfiguration.Category.ProfileConfigurations.OrderBy(p => p.Order).TakeWhile(c => c != ProfileConfiguration))
|
||||
{
|
||||
if (profileConfiguration != ProfileConfiguration)
|
||||
profileConfiguration.IsSuspended = action == "suspend";
|
||||
}
|
||||
}
|
||||
|
||||
public void SuspendBelow(string action)
|
||||
{
|
||||
foreach (ProfileConfiguration profileConfiguration in ProfileConfiguration.Category.ProfileConfigurations.OrderBy(p => p.Order).SkipWhile(c => c != ProfileConfiguration))
|
||||
{
|
||||
if (profileConfiguration != ProfileConfiguration)
|
||||
profileConfiguration.IsSuspended = action == "suspend";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Export()
|
||||
{
|
||||
string filename = new string(ProfileConfiguration.Name.Select(ch => Path.GetInvalidFileNameChars().Contains(ch) ? '_' : ch).ToArray()) + ".json";
|
||||
VistaSaveFileDialog dialog = new()
|
||||
{
|
||||
Filter = "Artemis Profile|*.json",
|
||||
Title = "Export Artemis profile",
|
||||
FileName = filename
|
||||
};
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result != true)
|
||||
return;
|
||||
|
||||
ProfileConfigurationExportModel profileConfigurationExportModel = _profileService.ExportProfile(ProfileConfiguration);
|
||||
string json = JsonConvert.SerializeObject(profileConfigurationExportModel, IProfileService.ExportSettings);
|
||||
|
||||
if (!dialog.FileName.EndsWith(".json"))
|
||||
dialog.FileName += ".json";
|
||||
await File.WriteAllTextAsync(dialog.FileName, json);
|
||||
}
|
||||
|
||||
public void Duplicate()
|
||||
{
|
||||
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
|
||||
_profileService.ImportProfile(ProfileConfiguration.Category, export, true, false, "copy");
|
||||
}
|
||||
|
||||
public void Copy()
|
||||
{
|
||||
JsonClipboard.SetObject(_profileService.ExportProfile(ProfileConfiguration));
|
||||
}
|
||||
|
||||
public void Paste()
|
||||
{
|
||||
ProfileConfigurationExportModel profileConfiguration = JsonClipboard.GetData<ProfileConfigurationExportModel>();
|
||||
if (profileConfiguration == null)
|
||||
return;
|
||||
|
||||
_profileService.ImportProfile(ProfileConfiguration.Category, profileConfiguration, true, false, "copy");
|
||||
}
|
||||
|
||||
public async Task Delete()
|
||||
{
|
||||
if (await _dialogService.ShowConfirmDialog("Delete profile", "Are you sure you want to delete this profile?\r\nThis cannot be undone."))
|
||||
{
|
||||
// Close the editor first by heading to Home if the profile is being edited
|
||||
if (ProfileConfiguration.IsBeingEdited)
|
||||
_eventAggregator.Publish(new RequestSelectSidebarItemEvent("Home"));
|
||||
|
||||
_profileService.RemoveProfileConfiguration(ProfileConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
||||
ProfileConfiguration.PropertyChanged += ProfileConfigurationOnPropertyChanged;
|
||||
NotifyOfPropertyChange(nameof(IsProfileActive));
|
||||
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
ProfileConfiguration.PropertyChanged -= ProfileConfigurationOnPropertyChanged;
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ProfileConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(ProfileConfiguration.Profile))
|
||||
NotifyOfPropertyChange(nameof(IsProfileActive));
|
||||
if (e.PropertyName == nameof(ProfileConfiguration.IsSuspended))
|
||||
NotifyOfPropertyChange(nameof(IsSuspended));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Sidebar.SidebarScreenView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:SidebarScreenViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="{Binding Icon}" Width="16" Height="16" />
|
||||
<TextBlock FontSize="12" Margin="10 0" VerticalAlignment="Center" Text="{Binding DisplayName}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,31 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Ninject;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
public class SidebarScreenViewModel<T> : SidebarScreenViewModel where T : Screen
|
||||
{
|
||||
public SidebarScreenViewModel(PackIconKind icon, string displayName) : base(icon, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
public override Screen CreateInstance(IKernel kernel)
|
||||
{
|
||||
return kernel.Get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class SidebarScreenViewModel
|
||||
{
|
||||
protected SidebarScreenViewModel(PackIconKind icon, string displayName)
|
||||
{
|
||||
Icon = icon;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public abstract Screen CreateInstance(IKernel kernel);
|
||||
public PackIconKind Icon { get; }
|
||||
public string DisplayName { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,56 +4,163 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:sidebar="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||
xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance sidebar:SidebarViewModel}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ArtemisSidebar.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<materialDesign:DialogHost IsTabStop="False" Focusable="False" Identifier="SidebarDialog" DialogTheme="Inherit" DialogMargin="14">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Source="/Resources/Images/Sidebar/sidebar-header.png"
|
||||
Stretch="UniformToFill"
|
||||
VerticalAlignment="Top" Height="120" />
|
||||
<Grid Grid.Row="0" ClipToBounds="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ToggleButton Grid.Row="0"
|
||||
Style="{StaticResource MaterialDesignSwitchLightToggleButton}"
|
||||
ToolTip="Pin sidebar"
|
||||
HorizontalAlignment="Right"
|
||||
IsChecked="{Binding PinSidebar.Value, Delay=300}"
|
||||
Margin="10 0">
|
||||
<materialDesign:PackIcon Kind="Pin" RenderTransformOrigin=".5,.5">
|
||||
<materialDesign:PackIcon.RenderTransform>
|
||||
<RotateTransform Angle="45" />
|
||||
</materialDesign:PackIcon.RenderTransform>
|
||||
</materialDesign:PackIcon>
|
||||
<materialDesign:ToggleButtonAssist.OnContent>
|
||||
<materialDesign:PackIcon Kind="Pin" />
|
||||
</materialDesign:ToggleButtonAssist.OnContent>
|
||||
</ToggleButton>
|
||||
<shared:DeviceVisualizer Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Device="{Binding HeaderDevice}"
|
||||
ShowColors="True"
|
||||
RenderTransformOrigin="0.5 0.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
RenderOptions.BitmapScalingMode="HighQuality">
|
||||
<shared:DeviceVisualizer.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform Angle="20" />
|
||||
<ScaleTransform ScaleX="2" ScaleY="2" />
|
||||
</TransformGroup>
|
||||
</shared:DeviceVisualizer.RenderTransform>
|
||||
</shared:DeviceVisualizer>
|
||||
<Rectangle Grid.Column="0" Grid.ColumnSpan="2" Height="60" VerticalAlignment="Bottom">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
|
||||
<GradientStop Color="{Binding Path=Color, Source={StaticResource MaterialDesignToolBarBackground}}" Offset="0" /> <!-- TODO: Get the color from MaterialDesign -->
|
||||
<GradientStop Color="#00000000" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Image Grid.Column="0" Source="{svgc:SvgImage Source=/Resources/Images/Logo/bow.svg}" Height="35" Width="35" Margin="10" />
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource MaterialDesignHeadline5TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignDarkForeground}">
|
||||
Artemis 2
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignHeadline6TextBlock}"
|
||||
Foreground="{StaticResource PrimaryHueDarkForegroundBrush}"
|
||||
Margin="15"
|
||||
materialDesign:ShadowAssist.ShadowDepth="Depth1"
|
||||
Text="{Binding ActiveModules}"
|
||||
VerticalAlignment="Bottom" />
|
||||
<!-- Built-in screens -->
|
||||
<ListBox Grid.Row="1"
|
||||
Margin="0 2"
|
||||
ItemContainerStyle="{StaticResource SidebarListBoxItem}"
|
||||
ItemsSource="{Binding SidebarScreens}"
|
||||
SelectedItem="{Binding SelectedSidebarScreen}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Separator Grid.Row="2" Margin="8" />
|
||||
|
||||
<controls:SideNavigation Grid.Row="3"
|
||||
Items="{Binding SidebarItems}"
|
||||
SelectedItem="{Binding SelectedItem}"
|
||||
WillSelectNavigationItemCommand="{s:Action SelectItem}"
|
||||
materialDesign:RippleAssist.Feedback="{StaticResource SecondaryHueMidBrush}"
|
||||
Margin="0 5 0 0" />
|
||||
</Grid>
|
||||
<!-- Categories -->
|
||||
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
|
||||
<ScrollViewer.Resources>
|
||||
<Style TargetType="ScrollBar" BasedOn="{StaticResource MaterialDesignScrollBarMinimal}" />
|
||||
</ScrollViewer.Resources>
|
||||
<StackPanel>
|
||||
<StackPanel.Resources>
|
||||
<DataTemplate x:Key="CategoryDragTemplate" DataType="{x:Type sidebar:SidebarCategoryViewModel}">
|
||||
<DataTemplate.Resources>
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
</DataTemplate.Resources>
|
||||
<Border Background="{DynamicResource MaterialDesignTextFieldBoxHoverBackground}"
|
||||
Padding="10"
|
||||
CornerRadius="4"
|
||||
Visibility="{Binding Path=ProfileCategory, FallbackValue=null, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
<TextBlock Text="{Binding ProfileCategory.Name,TargetNullValue='Oops, I am missing'}" VerticalAlignment="Center" Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</StackPanel.Resources>
|
||||
<ItemsControl ItemsSource="{Binding Items}"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.DragAdornerTemplate="{StaticResource CategoryDragTemplate}"
|
||||
dd:DragDrop.DropHandler="{Binding}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Content="ADD NEW CATEGORY" Margin="10 10 10 0" Command="{s:Action AddCategory}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Bottom buttons -->
|
||||
<Separator Grid.Row="4" Margin="8" />
|
||||
<StackPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5 0 5 5">
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip="View website"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://artemis-rgb.com">
|
||||
<materialDesign:PackIcon Kind="Web" Width="20" Height="20" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip="View GitHub repository"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/Artemis-RGB/Artemis">
|
||||
<materialDesign:PackIcon Kind="Github" Width="20" Height="20" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip="View Wiki"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com">
|
||||
<materialDesign:PackIcon Kind="BookOpenOutline" Width="20" Height="20" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip="Join our Discord"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://discord.gg/S3MVaC9">
|
||||
<materialDesign:PackIcon Kind="Discord" Width="20" Height="20" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip="View donation options"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/en/donating">
|
||||
<materialDesign:PackIcon Kind="Gift" Width="20" Height="20" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</UserControl>
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SidebarView.xaml
|
||||
/// </summary>
|
||||
public partial class SidebarView : UserControl
|
||||
{
|
||||
public SidebarView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,285 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.Home;
|
||||
using Artemis.UI.Screens.Modules;
|
||||
using Artemis.UI.Screens.News;
|
||||
using Artemis.UI.Screens.ProfileEditor;
|
||||
using Artemis.UI.Screens.Settings;
|
||||
using Artemis.UI.Screens.Sidebar.Dialogs;
|
||||
using Artemis.UI.Screens.SurfaceEditor;
|
||||
using Artemis.UI.Screens.Workshop;
|
||||
using Artemis.UI.Shared;
|
||||
using MaterialDesignExtensions.Controls;
|
||||
using MaterialDesignExtensions.Model;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using GongSolutions.Wpf.DragDrop;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Ninject;
|
||||
using RGB.NET.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
public sealed class SidebarViewModel : Screen, IHandle<RequestSelectSidebarItemEvent>, IDisposable
|
||||
public sealed class SidebarViewModel : Conductor<SidebarCategoryViewModel>.Collection.AllActive, IHandle<RequestSelectSidebarItemEvent>, IDropTarget
|
||||
{
|
||||
private readonly Timer _activeModulesUpdateTimer;
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IModuleVmFactory _moduleVmFactory;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly IModuleService _moduleService;
|
||||
private string _activeModules;
|
||||
private bool _isSidebarOpen;
|
||||
private IScreen _selectedItem;
|
||||
private BindableCollection<INavigationItem> _sidebarItems;
|
||||
private Dictionary<INavigationItem, Module> _sidebarModules;
|
||||
private readonly ISidebarVmFactory _sidebarVmFactory;
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IDialogService _dialogService;
|
||||
private SidebarScreenViewModel _selectedSidebarScreen;
|
||||
private ArtemisDevice _headerDevice;
|
||||
private Screen _selectedScreen;
|
||||
private readonly SidebarScreenViewModel<ProfileEditorViewModel> _profileEditor;
|
||||
private readonly DefaultDropHandler _defaultDropHandler;
|
||||
|
||||
public SidebarViewModel(IKernel kernel, ISettingsService settingsService, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService, IModuleService moduleService)
|
||||
public SidebarViewModel(IKernel kernel,
|
||||
IEventAggregator eventAggregator,
|
||||
ISidebarVmFactory sidebarVmFactory,
|
||||
IRgbService rgbService,
|
||||
IProfileService profileService,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService)
|
||||
{
|
||||
_kernel = kernel;
|
||||
_moduleVmFactory = moduleVmFactory;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_moduleService = moduleService;
|
||||
_sidebarVmFactory = sidebarVmFactory;
|
||||
_rgbService = rgbService;
|
||||
_profileService = profileService;
|
||||
_profileEditorService = profileEditorService;
|
||||
_dialogService = dialogService;
|
||||
_profileEditor = new SidebarScreenViewModel<ProfileEditorViewModel>(PackIconKind.Wrench, "Profile Editor");
|
||||
_defaultDropHandler = new DefaultDropHandler();
|
||||
|
||||
SidebarModules = new Dictionary<INavigationItem, Module>();
|
||||
SidebarItems = new BindableCollection<INavigationItem>();
|
||||
PinSidebar = settingsService.GetSetting("UI.PinSidebar", false);
|
||||
PinSidebar.AutoSave = true;
|
||||
|
||||
_activeModulesUpdateTimer = new Timer(1000);
|
||||
eventAggregator.Subscribe(this);
|
||||
|
||||
SidebarScreens = new BindableCollection<SidebarScreenViewModel>
|
||||
{
|
||||
new SidebarScreenViewModel<HomeViewModel>(PackIconKind.Home, "Home"),
|
||||
new SidebarScreenViewModel<WorkshopViewModel>(PackIconKind.TestTube, "Workshop"),
|
||||
new SidebarScreenViewModel<SurfaceEditorViewModel>(PackIconKind.Devices, "Surface Editor"),
|
||||
new SidebarScreenViewModel<SettingsViewModel>(PackIconKind.Cog, "Settings")
|
||||
};
|
||||
SelectedSidebarScreen = SidebarScreens.First();
|
||||
UpdateProfileCategories();
|
||||
UpdateHeaderDevice();
|
||||
}
|
||||
|
||||
public PluginSetting<bool> PinSidebar { get; }
|
||||
|
||||
public BindableCollection<INavigationItem> SidebarItems
|
||||
private void UpdateHeaderDevice()
|
||||
{
|
||||
get => _sidebarItems;
|
||||
set => SetAndNotify(ref _sidebarItems, value);
|
||||
HeaderDevice = _rgbService.Devices.FirstOrDefault(d => d.DeviceType == RGBDeviceType.Keyboard && d.Layout.IsValid);
|
||||
}
|
||||
|
||||
public Dictionary<INavigationItem, Module> SidebarModules
|
||||
public ArtemisDevice HeaderDevice
|
||||
{
|
||||
get => _sidebarModules;
|
||||
set => SetAndNotify(ref _sidebarModules, value);
|
||||
get => _headerDevice;
|
||||
set => SetAndNotify(ref _headerDevice, value);
|
||||
}
|
||||
|
||||
public string ActiveModules
|
||||
public BindableCollection<SidebarScreenViewModel> SidebarScreens { get; }
|
||||
|
||||
public Screen SelectedScreen
|
||||
{
|
||||
get => _activeModules;
|
||||
set => SetAndNotify(ref _activeModules, value);
|
||||
get => _selectedScreen;
|
||||
private set => SetAndNotify(ref _selectedScreen, value);
|
||||
}
|
||||
|
||||
public IScreen SelectedItem
|
||||
public SidebarScreenViewModel SelectedSidebarScreen
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => SetAndNotify(ref _selectedItem, value);
|
||||
}
|
||||
|
||||
public bool IsSidebarOpen
|
||||
{
|
||||
get => _isSidebarOpen;
|
||||
get => _selectedSidebarScreen;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isSidebarOpen, value);
|
||||
if (value)
|
||||
ActiveModulesUpdateTimerOnElapsed(this, EventArgs.Empty);
|
||||
if (SetAndNotify(ref _selectedSidebarScreen, value))
|
||||
ActivateScreenViewModel(_selectedSidebarScreen);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupSidebar()
|
||||
private void ActivateScreenViewModel(SidebarScreenViewModel screenViewModel)
|
||||
{
|
||||
UpdateSidebarItems();
|
||||
|
||||
// Set the sidebar as open if it's pinned
|
||||
if (PinSidebar.Value)
|
||||
IsSidebarOpen = true;
|
||||
|
||||
// Select the top item, which will be one of the defaults
|
||||
Task.Run(() => SelectSidebarItem(SidebarItems[0]));
|
||||
SelectedScreen = screenViewModel.CreateInstance(_kernel);
|
||||
OnSelectedScreenChanged();
|
||||
if (screenViewModel != _profileEditor)
|
||||
SelectProfileConfiguration(null);
|
||||
}
|
||||
|
||||
private void UpdateSidebarItems()
|
||||
private void UpdateProfileCategories()
|
||||
{
|
||||
SidebarItems.Clear();
|
||||
SidebarModules.Clear();
|
||||
|
||||
// Add all default sidebar items
|
||||
SidebarItems.Add(new FirstLevelNavigationItem { Icon = PackIconKind.Home, Label = "Home" });
|
||||
SidebarItems.Add(new FirstLevelNavigationItem { Icon = PackIconKind.Newspaper, Label = "News" });
|
||||
SidebarItems.Add(new FirstLevelNavigationItem { Icon = PackIconKind.TestTube, Label = "Workshop" });
|
||||
SidebarItems.Add(new FirstLevelNavigationItem { Icon = PackIconKind.Edit, Label = "Surface Editor" });
|
||||
SidebarItems.Add(new FirstLevelNavigationItem { Icon = PackIconKind.Settings, Label = "Settings" });
|
||||
|
||||
// Add all activated modules
|
||||
SidebarItems.Add(new DividerNavigationItem());
|
||||
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>().ToList();
|
||||
|
||||
foreach (IGrouping<ModulePriorityCategory, Module> category in modules.OrderByDescending(m => m.PriorityCategory).GroupBy(m => m.PriorityCategory))
|
||||
{
|
||||
SidebarItems.Add(new SubheaderNavigationItem { Subheader = category.Key.ToString() });
|
||||
foreach(Module module in category.OrderBy(m => m.Priority))
|
||||
{
|
||||
AddModule(module);
|
||||
}
|
||||
}
|
||||
foreach (ProfileCategory profileCategory in _profileService.ProfileCategories.OrderBy(p => p.Order))
|
||||
AddProfileCategoryViewModel(profileCategory);
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called by view
|
||||
public void SelectItem(WillSelectNavigationItemEventArgs args)
|
||||
public async Task AddCategory()
|
||||
{
|
||||
if (args.NavigationItemToSelect == null)
|
||||
{
|
||||
SelectedItem = null;
|
||||
return;
|
||||
}
|
||||
object result = await _dialogService.ShowDialog<SidebarCategoryCreateViewModel>();
|
||||
if (result is ProfileCategory profileCategory)
|
||||
AddProfileCategoryViewModel(profileCategory);
|
||||
|
||||
SelectSidebarItem(args.NavigationItemToSelect);
|
||||
((BindableCollection<SidebarCategoryViewModel>) Items).Sort(p => p.ProfileCategory.Order);
|
||||
}
|
||||
|
||||
public void AddModule(Module module)
|
||||
public void OpenUrl(string url)
|
||||
{
|
||||
// Ensure the module is not already in the list
|
||||
if (SidebarModules.Any(io => io.Value == module))
|
||||
return;
|
||||
|
||||
FirstLevelNavigationItem sidebarItem = new()
|
||||
{
|
||||
Icon = PluginUtilities.GetPluginIcon(module.Plugin, module.DisplayIcon),
|
||||
Label = module.DisplayName
|
||||
};
|
||||
SidebarItems.Add(sidebarItem);
|
||||
SidebarModules.Add(sidebarItem, module);
|
||||
}
|
||||
|
||||
public void RemoveModule(Module module)
|
||||
{
|
||||
// If not in the list there's nothing to do
|
||||
if (SidebarModules.All(io => io.Value != module))
|
||||
return;
|
||||
|
||||
KeyValuePair<INavigationItem, Module> existing = SidebarModules.First(io => io.Value == module);
|
||||
SidebarItems.Remove(existing.Key);
|
||||
SidebarModules.Remove(existing.Key);
|
||||
}
|
||||
|
||||
private void ActiveModulesUpdateTimerOnElapsed(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsSidebarOpen)
|
||||
return;
|
||||
|
||||
int activeModules = SidebarModules.Count(m => m.Value.IsActivated);
|
||||
ActiveModules = activeModules == 1 ? "1 active module" : $"{activeModules} active modules";
|
||||
}
|
||||
|
||||
private void SelectSidebarItem(INavigationItem sidebarItem)
|
||||
{
|
||||
// A module was selected if the dictionary contains the selected item
|
||||
if (SidebarModules.ContainsKey(sidebarItem))
|
||||
ActivateModule(sidebarItem);
|
||||
else if (sidebarItem is FirstLevelNavigationItem navigationItem)
|
||||
ActivateViewModel(navigationItem.Label);
|
||||
else
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
private void ActivateViewModel(string label)
|
||||
{
|
||||
if (label == "Home")
|
||||
ActivateViewModel<HomeViewModel>();
|
||||
else if (label == "News")
|
||||
ActivateViewModel<NewsViewModel>();
|
||||
else if (label == "Workshop")
|
||||
ActivateViewModel<WorkshopViewModel>();
|
||||
else if (label == "Surface Editor")
|
||||
ActivateViewModel<SurfaceEditorViewModel>();
|
||||
else if (label == "Settings")
|
||||
ActivateViewModel<SettingsViewModel>();
|
||||
}
|
||||
|
||||
private void ActivateViewModel<T>()
|
||||
{
|
||||
if (SelectedItem != null && SelectedItem.GetType() == typeof(T))
|
||||
return;
|
||||
SelectedItem = (IScreen) _kernel.Get<T>();
|
||||
}
|
||||
|
||||
private void ActivateModule(INavigationItem sidebarItem)
|
||||
{
|
||||
if (!SidebarModules.ContainsKey(sidebarItem))
|
||||
return;
|
||||
if (SelectedItem is ModuleRootViewModel moduleRootViewModel && moduleRootViewModel.Module == SidebarModules[sidebarItem])
|
||||
return;
|
||||
|
||||
SelectedItem = _moduleVmFactory.CreateModuleRootViewModel(SidebarModules[sidebarItem]);
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_activeModulesUpdateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void OnFeatureEnabled(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature is Module)
|
||||
UpdateSidebarItems();
|
||||
}
|
||||
|
||||
private void OnFeatureDisabled(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature is Module)
|
||||
UpdateSidebarItems();
|
||||
}
|
||||
|
||||
private void OnModulePriorityUpdated(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSidebarItems();
|
||||
Core.Utilities.OpenUrl(url);
|
||||
}
|
||||
|
||||
public void Handle(RequestSelectSidebarItemEvent message)
|
||||
{
|
||||
ActivateViewModel(message.Label);
|
||||
SidebarScreenViewModel requested = SidebarScreens.FirstOrDefault(s => s.DisplayName == message.DisplayName);
|
||||
if (requested != null)
|
||||
SelectedSidebarScreen = requested;
|
||||
}
|
||||
|
||||
#endregion
|
||||
public SidebarCategoryViewModel AddProfileCategoryViewModel(ProfileCategory profileCategory)
|
||||
{
|
||||
SidebarCategoryViewModel viewModel = _sidebarVmFactory.SidebarCategoryViewModel(profileCategory);
|
||||
Items.Add(viewModel);
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
public void RemoveProfileCategoryViewModel(SidebarCategoryViewModel viewModel)
|
||||
{
|
||||
Items.Remove(viewModel);
|
||||
}
|
||||
|
||||
public void SelectProfileConfiguration(ProfileConfiguration profileConfiguration)
|
||||
{
|
||||
foreach (SidebarCategoryViewModel sidebarCategoryViewModel in Items)
|
||||
sidebarCategoryViewModel.SelectedProfileConfiguration = sidebarCategoryViewModel.Items.FirstOrDefault(i => i.ProfileConfiguration == profileConfiguration);
|
||||
|
||||
_profileEditorService.ChangeSelectedProfileConfiguration(profileConfiguration);
|
||||
if (profileConfiguration != null)
|
||||
{
|
||||
// Little workaround to clear the selected item in the menu, ugly but oh well
|
||||
if (_selectedSidebarScreen != _profileEditor)
|
||||
{
|
||||
_selectedSidebarScreen = null;
|
||||
NotifyOfPropertyChange(nameof(SelectedSidebarScreen));
|
||||
}
|
||||
|
||||
SelectedSidebarScreen = _profileEditor;
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_activeModulesUpdateTimer.Start();
|
||||
_activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed;
|
||||
|
||||
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnabled;
|
||||
_pluginManagementService.PluginFeatureDisabled += OnFeatureDisabled;
|
||||
_moduleService.ModulePriorityUpdated += OnModulePriorityUpdated;
|
||||
|
||||
SetupSidebar();
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_activeModulesUpdateTimer.Stop();
|
||||
_activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
|
||||
|
||||
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnabled;
|
||||
_pluginManagementService.PluginFeatureDisabled -= OnFeatureDisabled;
|
||||
_moduleService.ModulePriorityUpdated -= OnModulePriorityUpdated;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler SelectedScreenChanged;
|
||||
|
||||
private void OnSelectedScreenChanged()
|
||||
{
|
||||
SelectedScreenChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDropTarget
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DragOver(IDropInfo dropInfo)
|
||||
{
|
||||
_defaultDropHandler.DragOver(dropInfo);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Drop(IDropInfo dropInfo)
|
||||
{
|
||||
_defaultDropHandler.Drop(dropInfo);
|
||||
for (int index = 0; index < Items.Count; index++)
|
||||
Items[index].ProfileCategory.Order = index;
|
||||
|
||||
// Bit dumb but gets the job done
|
||||
foreach (SidebarCategoryViewModel viewModel in Items)
|
||||
_profileService.SaveProfileCategory(viewModel.ProfileCategory);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,10 @@
|
||||
using System.Windows.Navigation;
|
||||
using Artemis.Core.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.StartupWizard.Steps
|
||||
{
|
||||
public class FinishStepViewModel : Screen
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
|
||||
public FinishStepViewModel(ICoreService coreService)
|
||||
{
|
||||
_coreService = coreService;
|
||||
}
|
||||
|
||||
public void OpenHyperlink(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
Core.Utilities.OpenUrl(e.Uri.AbsoluteUri);
|
||||
@@ -22,11 +14,5 @@ namespace Artemis.UI.Screens.StartupWizard.Steps
|
||||
{
|
||||
((StartupWizardViewModel) Parent).SkipOrFinishWizard();
|
||||
}
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
_coreService.PlayIntroAnimation();
|
||||
base.OnActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
MouseLeave="{s:Action MouseLeave}"
|
||||
ToolTip="{Binding Device.RgbDevice.DeviceInfo.DeviceName}">
|
||||
<UserControl.Resources>
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<!-- Content -->
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
<materialDesign:PackIcon Kind="Home" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="News" Command="{s:Action TrayActivateSidebarItem}" CommandParameter="News">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="Newspaper" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Workshop" Command="{s:Action TrayActivateSidebarItem}" CommandParameter="Workshop">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="TestTube" />
|
||||
|
||||
Reference in new issue
Block a user