1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Added profile hierarchy creation and editing (doesn't save yet)

This commit is contained in:
SpoinkyNL 2019-11-23 23:56:07 +01:00
parent ff959b6f9c
commit 1bb2d4a4f2
43 changed files with 676 additions and 241 deletions

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
@ -6,15 +8,26 @@ namespace Artemis.Core.Models.Profile.Abstract
{ {
public abstract class ProfileElement public abstract class ProfileElement
{ {
protected List<ProfileElement> _children;
protected ProfileElement()
{
_children = new List<ProfileElement>();
}
public Guid EntityId { get; internal set; }
public Profile Profile { get; internal set; }
public ProfileElement Parent { get; internal set; }
/// <summary> /// <summary>
/// The element's children /// The element's children
/// </summary> /// </summary>
public List<ProfileElement> Children { get; set; } public ReadOnlyCollection<ProfileElement> Children => _children.AsReadOnly();
/// <summary> /// <summary>
/// The order in which this element appears in the update loop and editor /// The order in which this element appears in the update loop and editor
/// </summary> /// </summary>
public int Order { get; set; } public int Order { get; internal set; }
/// <summary> /// <summary>
/// The name which appears in the editor /// The name which appears in the editor
@ -60,5 +73,58 @@ namespace Artemis.Core.Models.Profile.Abstract
return folders; return folders;
} }
/// <summary>
/// Adds a profile element to the <see cref="Children" /> collection, optionally at the given position (1-based)
/// </summary>
/// <param name="child">The profile element to add</param>
/// <param name="order">The order where to place the child (1-based), defaults to the end of the collection</param>
public void AddChild(ProfileElement child, int? order = null)
{
lock (_children)
{
// Add to the end of the list
if (order == null)
{
_children.Add(child);
child.Order = _children.Count;
return;
}
// Shift everything after the given order
foreach (var profileElement in _children.Where(c => c.Order >= order).ToList())
profileElement.Order++;
int targetIndex;
if (order == 0)
targetIndex = 0;
else if (order > _children.Count)
targetIndex = _children.Count;
else
targetIndex = _children.FindIndex(c => c.Order == order + 1);
_children.Insert(targetIndex, child);
child.Order = order.Value;
child.Parent = this;
}
}
/// <summary>
/// Removes a profile element from the <see cref="Children" /> collection
/// </summary>
/// <param name="child">The profile element to remove</param>
public void RemoveChild(ProfileElement child)
{
lock (_children)
{
_children.Remove(child);
// Shift everything after the given order
foreach (var profileElement in _children.Where(c => c.Order > child.Order).ToList())
profileElement.Order--;
child.Parent = null;
}
}
} }
} }

View File

@ -10,40 +10,41 @@ namespace Artemis.Core.Models.Profile
{ {
public sealed class Folder : ProfileElement public sealed class Folder : ProfileElement
{ {
public Folder(Profile profile, Folder folder, string name) public Folder(Profile profile, ProfileElement parent, string name)
{ {
FolderEntity = new FolderEntity(); FolderEntity = new FolderEntity();
EntityId = Guid.NewGuid(); EntityId = Guid.NewGuid();
Profile = profile; Profile = profile;
ParentFolder = folder; Parent = parent;
Name = name; Name = name;
Children = new List<ProfileElement>();
} }
public Folder(Profile profile, Folder folder, FolderEntity folderEntity, IPluginService pluginService) public Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity, IPluginService pluginService)
{ {
FolderEntity = folderEntity; FolderEntity = folderEntity;
EntityId = folderEntity.Id; EntityId = folderEntity.Id;
Profile = profile; Profile = profile;
ParentFolder = folder; Parent = parent;
Children = new List<ProfileElement>();
// Load child folders // Load child folders
foreach (var childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId)) foreach (var childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
folder.Children.Add(new Folder(profile, this, childFolder, pluginService)); _children.Add(new Folder(profile, this, childFolder, pluginService));
// Load child layers // Load child layers
foreach (var childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId)) foreach (var childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId))
folder.Children.Add(new Layer(profile, this, childLayer, pluginService)); _children.Add(new Layer(profile, this, childLayer, pluginService));
// Ensure order integrity, should be unnecessary but no one is perfect specially me
_children = _children.OrderBy(c => c.Order).ToList();
for (var index = 0; index < _children.Count; index++)
{
var profileElement = _children[index];
profileElement.Order = index + 1;
}
} }
internal FolderEntity FolderEntity { get; set; } internal FolderEntity FolderEntity { get; set; }
internal Guid EntityId { get; set; }
public Profile Profile { get; }
public Folder ParentFolder { get; }
public override void Update(double deltaTime) public override void Update(double deltaTime)
{ {
@ -59,10 +60,24 @@ namespace Artemis.Core.Models.Profile
profileElement.Render(deltaTime, surface, graphics); profileElement.Render(deltaTime, surface, graphics);
} }
public Folder AddFolder(string name)
{
var folder = new Folder(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
AddChild(folder);
return folder;
}
public Layer AddLayer(string name)
{
var layer = new Layer(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
AddChild(layer);
return layer;
}
internal override void ApplyToEntity() internal override void ApplyToEntity()
{ {
FolderEntity.Id = EntityId; FolderEntity.Id = EntityId;
FolderEntity.ParentId = ParentFolder?.EntityId ?? new Guid(); FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
FolderEntity.Order = Order; FolderEntity.Order = Order;
FolderEntity.Name = Name; FolderEntity.Name = Name;
@ -74,7 +89,7 @@ namespace Artemis.Core.Models.Profile
public override string ToString() public override string ToString()
{ {
return $"{nameof(Profile)}: {Profile}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}"; return $"Folder - {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
} }
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Linq; using System.Linq;
using System.Reflection.Metadata.Ecma335;
using Artemis.Core.Extensions; using Artemis.Core.Extensions;
using Artemis.Core.Models.Profile.Abstract; using Artemis.Core.Models.Profile.Abstract;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
@ -16,33 +17,29 @@ namespace Artemis.Core.Models.Profile
{ {
public sealed class Layer : ProfileElement public sealed class Layer : ProfileElement
{ {
internal Layer(Profile profile, Folder folder, string name) internal Layer(Profile profile, ProfileElement parent, string name)
{ {
LayerEntity = new LayerEntity(); LayerEntity = new LayerEntity();
EntityId = Guid.NewGuid(); EntityId = Guid.NewGuid();
Profile = profile; Profile = profile;
ParentFolder = folder; Parent = parent;
Name = name; Name = name;
Leds = new List<DeviceLed>(); Leds = new List<DeviceLed>();
} }
internal Layer(Profile profile, Folder folder, LayerEntity layerEntity, IPluginService pluginService) internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity, IPluginService pluginService)
{ {
LayerEntity = layerEntity; LayerEntity = layerEntity;
EntityId = layerEntity.Id; EntityId = layerEntity.Id;
Profile = profile; Profile = profile;
ParentFolder = folder; Parent = parent;
LayerType = pluginService.GetLayerTypeByGuid(layerEntity.LayerTypeGuid); LayerType = pluginService.GetLayerTypeByGuid(layerEntity.LayerTypeGuid);
Leds = new List<DeviceLed>(); Leds = new List<DeviceLed>();
} }
internal LayerEntity LayerEntity { get; set; } internal LayerEntity LayerEntity { get; set; }
internal Guid EntityId { get; set; }
public Profile Profile { get; }
public Folder ParentFolder { get; }
public List<DeviceLed> Leds { get; private set; } public List<DeviceLed> Leds { get; private set; }
public LayerType LayerType { get; private set; } public LayerType LayerType { get; private set; }
@ -76,7 +73,7 @@ namespace Artemis.Core.Models.Profile
internal override void ApplyToEntity() internal override void ApplyToEntity()
{ {
LayerEntity.Id = EntityId; LayerEntity.Id = EntityId;
LayerEntity.ParentId = ParentFolder?.EntityId ?? new Guid(); LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
LayerEntity.LayerTypeGuid = LayerType?.PluginInfo.Guid ?? new Guid(); LayerEntity.LayerTypeGuid = LayerType?.PluginInfo.Guid ?? new Guid();
LayerEntity.Order = Order; LayerEntity.Order = Order;
@ -135,7 +132,7 @@ namespace Artemis.Core.Models.Profile
public override string ToString() public override string ToString()
{ {
return $"{nameof(Profile)}: {Profile}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}"; return $"Layer - {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
} }
} }
} }

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using Artemis.Core.Exceptions; using Artemis.Core.Exceptions;
@ -20,8 +19,7 @@ namespace Artemis.Core.Models.Profile
PluginInfo = pluginInfo; PluginInfo = pluginInfo;
Name = name; Name = name;
Children = new List<ProfileElement> {new Folder(this, null, "Root folder")}; AddChild(new Folder(this, null, "Root folder"));
ApplyToEntity(); ApplyToEntity();
} }
@ -36,16 +34,15 @@ namespace Artemis.Core.Models.Profile
// Populate the profile starting at the root, the rest is populated recursively // Populate the profile starting at the root, the rest is populated recursively
var rootFolder = profileEntity.Folders.FirstOrDefault(f => f.ParentId == new Guid()); var rootFolder = profileEntity.Folders.FirstOrDefault(f => f.ParentId == new Guid());
if (rootFolder == null) if (rootFolder == null)
Children = new List<ProfileElement> {new Folder(this, null, "Root folder")}; AddChild(new Folder(this, null, "Root folder"));
else else
Children = new List<ProfileElement> {new Folder(this, null, rootFolder, pluginService)}; AddChild(new Folder(this, null, rootFolder, pluginService));
} }
public PluginInfo PluginInfo { get; } public PluginInfo PluginInfo { get; }
public bool IsActivated { get; private set; } public bool IsActivated { get; private set; }
internal ProfileEntity ProfileEntity { get; set; } internal ProfileEntity ProfileEntity { get; set; }
public Guid EntityId { get; set; }
public override void Update(double deltaTime) public override void Update(double deltaTime)
{ {
@ -116,6 +113,12 @@ namespace Artemis.Core.Models.Profile
return $"{nameof(Order)}: {Order}, {nameof(Name)}: {Name}, {nameof(PluginInfo)}: {PluginInfo}"; return $"{nameof(Order)}: {Order}, {nameof(Name)}: {Name}, {nameof(PluginInfo)}: {PluginInfo}";
} }
public void ApplySurface(Surface.Surface surface)
{
foreach (var layer in GetAllLayers())
layer.ApplySurface(surface);
}
#region Events #region Events
/// <summary> /// <summary>
@ -139,11 +142,5 @@ namespace Artemis.Core.Models.Profile
} }
#endregion #endregion
public void ApplySurface(Surface.Surface surface)
{
foreach (var layer in GetAllLayers())
layer.ApplySurface(surface);
}
} }
} }

View File

@ -75,6 +75,9 @@
<Reference Include="FluentValidation, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7de548da2fbae0f0, processorArchitecture=MSIL"> <Reference Include="FluentValidation, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7de548da2fbae0f0, processorArchitecture=MSIL">
<HintPath>..\packages\FluentValidation.8.5.0\lib\net45\FluentValidation.dll</HintPath> <HintPath>..\packages\FluentValidation.8.5.0\lib\net45\FluentValidation.dll</HintPath>
</Reference> </Reference>
<Reference Include="GongSolutions.WPF.DragDrop, Version=2.0.0.0, Culture=neutral, PublicKeyToken=91f1945125b7a587, processorArchitecture=MSIL">
<HintPath>..\packages\gong-wpf-dragdrop.2.1.0\lib\net47\GongSolutions.WPF.DragDrop.dll</HintPath>
</Reference>
<Reference Include="Humanizer, Version=2.6.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL"> <Reference Include="Humanizer, Version=2.6.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
<HintPath>..\packages\Humanizer.Core.2.6.2\lib\netstandard2.0\Humanizer.dll</HintPath> <HintPath>..\packages\Humanizer.Core.2.6.2\lib\netstandard2.0\Humanizer.dll</HintPath>
</Reference> </Reference>
@ -170,8 +173,14 @@
<Compile Include="Screens\Module\ProfileEditor\ElementProperties\ElementPropertyViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\ElementProperties\ElementPropertyViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementsViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementsViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\LayerElements\LayerElementViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Layers\LayersViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\ProfileElements\FolderView.xaml.cs">
<DependentUpon>FolderView.xaml</DependentUpon>
</Compile>
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\FolderViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\LayerViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElementsViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\ProfileEditorPanelViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\ProfileEditorPanelViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\ProfileElements\Abstract\ProfileElementViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileViewModel.cs" />
<Compile Include="Screens\News\NewsViewModel.cs" /> <Compile Include="Screens\News\NewsViewModel.cs" />
<Compile Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigViewModelValidator.cs" /> <Compile Include="Screens\SurfaceEditor\Dialogs\SurfaceDeviceConfigViewModelValidator.cs" />
@ -235,7 +244,15 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Screens\Module\ProfileEditor\Layers\LayersView.xaml"> <Page Include="Screens\Module\ProfileEditor\ProfileElements\FolderView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\ProfileElements\LayerView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\ProfileElements\ProfileElementsView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
@ -374,6 +391,7 @@
<ItemGroup> <ItemGroup>
<None Include="Resources\aero_rotate_br.cur" /> <None Include="Resources\aero_rotate_br.cur" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent> <PostBuildEvent>

View File

@ -20,7 +20,7 @@
<dragablz:TabablzControl.ContentTemplate> <dragablz:TabablzControl.ContentTemplate>
<DataTemplate> <DataTemplate>
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect FadeIn}"> <materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
<ContentControl s:View.Model="{Binding}" IsTabStop="False"/> <ContentControl s:View.Model="{Binding}" IsTabStop="False" />
</materialDesign:TransitioningContent> </materialDesign:TransitioningContent>
</DataTemplate> </DataTemplate>
</dragablz:TabablzControl.ContentTemplate> </dragablz:TabablzControl.ContentTemplate>

View File

@ -36,7 +36,7 @@ namespace Artemis.UI.Screens.Module
var moduleViewModels = Module.GetViewModels(); var moduleViewModels = Module.GetViewModels();
Items.AddRange(moduleViewModels); Items.AddRange(moduleViewModels);
ActiveItem = Items.FirstOrDefault(); ActiveItem = Items.FirstOrDefault();
} }
} }

View File

@ -12,9 +12,9 @@
Add a new profile Add a new profile
</TextBlock> </TextBlock>
<TextBox materialDesign:HintAssist.Hint="Profile name" <TextBox materialDesign:HintAssist.Hint="Profile name"
Margin="0 8 0 16" Margin="0 8 0 16"
Style="{StaticResource MaterialDesignFloatingHintTextBox}" Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding ProfileName, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding ProfileName, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{ {
public class DisplayConditionViewModel public class DisplayConditionViewModel
{ {
} }
} }

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionsView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{ {
public class DisplayConditionsViewModel : ProfileEditorPanelViewModel public class DisplayConditionsViewModel : ProfileEditorPanelViewModel
{ {
} }
} }

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ElementProperties.ElementPropertiesView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ElementProperties.ElementPropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ElementProperties" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ElementProperties"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.ElementProperties
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.ElementProperties
{ {
public class ElementPropertiesViewModel : ProfileEditorPanelViewModel public class ElementPropertiesViewModel : ProfileEditorPanelViewModel
{ {
} }
} }

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ElementProperties.ElementPropertyView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ElementProperties.ElementPropertyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ElementProperties" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ElementProperties"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.ElementProperties
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.ElementProperties
{ {
public class ElementPropertyViewModel public class ElementPropertyViewModel
{ {
} }
} }

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerElements.LayerElementView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerElements.LayerElementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerElements" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerElements"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerElements
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerElements
{ {
public class LayerElementViewModel public class LayerElementViewModel
{ {
} }
} }

View File

@ -1,12 +1,10 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerElements.LayerElementsView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerElements.LayerElementsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerElements" xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerElements"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid />
</UserControl>
</Grid>
</UserControl>

View File

@ -1,12 +1,6 @@
using System; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerElements
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerElements
{ {
public class LayerElementsViewModel : ProfileEditorPanelViewModel public class LayerElementsViewModel : ProfileEditorPanelViewModel
{ {
} }
} }

View File

@ -1,12 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Layers.LayersView"
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.Module.ProfileEditor.Layers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
</Grid>
</UserControl>

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Screens.Module.ProfileEditor.Layers
{
public class LayersViewModel : ProfileEditorPanelViewModel
{
}
}

View File

@ -1,8 +1,14 @@
using Stylet; using Artemis.Core.Models.Profile;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor namespace Artemis.UI.Screens.Module.ProfileEditor
{ {
public class ProfileEditorPanelViewModel : Screen public class ProfileEditorPanelViewModel : Screen
{ {
public Profile Profile { get; set; }
public virtual void OnProfileChanged()
{
}
} }
} }

View File

@ -45,11 +45,11 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<ComboBox Name="LocaleCombo" <ComboBox Name="LocaleCombo"
Height="26" Height="26"
VerticalAlignment="Top" VerticalAlignment="Top"
ItemsSource="{Binding Profiles}" ItemsSource="{Binding Profiles}"
SelectedItem="{Binding SelectedProfile}" SelectedItem="{Binding SelectedProfile}"
DisplayMemberPath="Name"> DisplayMemberPath="Name">
<ComboBox.ItemsPanel> <ComboBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
@ -57,19 +57,19 @@
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ComboBox.ItemsPanel> </ComboBox.ItemsPanel>
</ComboBox> </ComboBox>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}" <Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Margin="10 0" Margin="10 0"
Grid.Column="1" Grid.Column="1"
Width="26" Width="26"
Height="26" Height="26"
VerticalAlignment="Top" VerticalAlignment="Top"
Command="{s:Action AddProfile}"> Command="{s:Action AddProfile}">
<materialDesign:PackIcon Kind="Add" Height="14" Width="14" /> <materialDesign:PackIcon Kind="Add" Height="14" Width="14" />
</Button> </Button>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}" <Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
Grid.Column="2" Grid.Column="2"
Width="26" Width="26"
Height="26" Height="26"
VerticalAlignment="Top" VerticalAlignment="Top"
Command="{s:Action DeleteActiveProfile}"> Command="{s:Action DeleteActiveProfile}">
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" /> <materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" />
@ -92,7 +92,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<materialDesign:Card Grid.Row="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch"> <materialDesign:Card Grid.Row="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch">
<ContentControl s:View.Model="{Binding LayersViewModel}" /> <ContentControl s:View.Model="{Binding ProfileElementsViewModel}" />
</materialDesign:Card> </materialDesign:Card>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" /> <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" Cursor="SizeNS" Margin="0 5" />

View File

@ -9,7 +9,7 @@ using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions; using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions;
using Artemis.UI.Screens.Module.ProfileEditor.ElementProperties; using Artemis.UI.Screens.Module.ProfileEditor.ElementProperties;
using Artemis.UI.Screens.Module.ProfileEditor.LayerElements; using Artemis.UI.Screens.Module.ProfileEditor.LayerElements;
using Artemis.UI.Screens.Module.ProfileEditor.Layers; using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements;
using Artemis.UI.Screens.Module.ProfileEditor.Visualization; using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Stylet; using Stylet;
@ -18,8 +18,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
{ {
public class ProfileEditorViewModel : Conductor<ProfileEditorPanelViewModel>.Collection.AllActive public class ProfileEditorViewModel : Conductor<ProfileEditorPanelViewModel>.Collection.AllActive
{ {
private readonly IProfileService _profileService;
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly IProfileService _profileService;
public ProfileEditorViewModel(ProfileModule module, ICollection<ProfileEditorPanelViewModel> viewModels, IProfileService profileService, IDialogService dialogService) public ProfileEditorViewModel(ProfileModule module, ICollection<ProfileEditorPanelViewModel> viewModels, IProfileService profileService, IDialogService dialogService)
{ {
@ -32,29 +32,32 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
DisplayConditionsViewModel = (DisplayConditionsViewModel) viewModels.First(vm => vm is DisplayConditionsViewModel); DisplayConditionsViewModel = (DisplayConditionsViewModel) viewModels.First(vm => vm is DisplayConditionsViewModel);
ElementPropertiesViewModel = (ElementPropertiesViewModel) viewModels.First(vm => vm is ElementPropertiesViewModel); ElementPropertiesViewModel = (ElementPropertiesViewModel) viewModels.First(vm => vm is ElementPropertiesViewModel);
LayerElementsViewModel = (LayerElementsViewModel) viewModels.First(vm => vm is LayerElementsViewModel); LayerElementsViewModel = (LayerElementsViewModel) viewModels.First(vm => vm is LayerElementsViewModel);
LayersViewModel = (LayersViewModel) viewModels.First(vm => vm is LayersViewModel); ProfileElementsViewModel = (ProfileElementsViewModel) viewModels.First(vm => vm is ProfileElementsViewModel);
ProfileViewModel = (ProfileViewModel) viewModels.First(vm => vm is ProfileViewModel); ProfileViewModel = (ProfileViewModel) viewModels.First(vm => vm is ProfileViewModel);
Profiles = new BindableCollection<Profile>(); Profiles = new BindableCollection<Profile>();
Items.AddRange(viewModels); Items.AddRange(viewModels);
module.ActiveProfileChanged += ModuleOnActiveProfileChanged; module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
} }
public ProfileModule Module { get; } public ProfileModule Module { get; }
public DisplayConditionsViewModel DisplayConditionsViewModel { get; } public DisplayConditionsViewModel DisplayConditionsViewModel { get; }
public ElementPropertiesViewModel ElementPropertiesViewModel { get; } public ElementPropertiesViewModel ElementPropertiesViewModel { get; }
public LayerElementsViewModel LayerElementsViewModel { get; } public LayerElementsViewModel LayerElementsViewModel { get; }
public LayersViewModel LayersViewModel { get; } public ProfileElementsViewModel ProfileElementsViewModel { get; }
public ProfileViewModel ProfileViewModel { get; } public ProfileViewModel ProfileViewModel { get; }
public BindableCollection<Profile> Profiles { get; set; } public BindableCollection<Profile> Profiles { get; set; }
public Profile SelectedProfile public Profile SelectedProfile
{ {
get => Module.ActiveProfile; get => Module.ActiveProfile;
set => ChangeSelectedProfile(value); set => ChangeSelectedProfile(value);
} }
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
private void ChangeSelectedProfile(Profile profile) private void ChangeSelectedProfile(Profile profile)
{ {
if (profile == Module.ActiveProfile) if (profile == Module.ActiveProfile)
@ -63,14 +66,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
var oldProfile = Module.ActiveProfile; var oldProfile = Module.ActiveProfile;
Module.ChangeActiveProfile(profile); Module.ChangeActiveProfile(profile);
foreach (var panelViewModel in Items)
{
panelViewModel.Profile = profile;
panelViewModel.OnProfileChanged();
}
if (oldProfile != null) if (oldProfile != null)
_profileService.UpdateProfile(oldProfile, false); _profileService.UpdateProfile(oldProfile, false);
if (profile != null) if (profile != null)
_profileService.UpdateProfile(profile, false); _profileService.UpdateProfile(profile, false);
} }
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
public Profile CreateProfile(string name) public Profile CreateProfile(string name)
{ {
var profile = _profileService.CreateProfile(Module, name); var profile = _profileService.CreateProfile(Module, name);
@ -130,11 +137,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
activeProfile = CreateProfile("Default"); activeProfile = CreateProfile("Default");
profiles.Add(activeProfile); profiles.Add(activeProfile);
} }
// GetActiveProfile can return a duplicate because inactive profiles aren't kept in memory, make sure it's unique in the profiles list // GetActiveProfile can return a duplicate because inactive profiles aren't kept in memory, make sure it's unique in the profiles list
profiles = profiles.Where(p => p.EntityId != activeProfile.EntityId).ToList(); profiles = profiles.Where(p => p.EntityId != activeProfile.EntityId).ToList();
profiles.Add(activeProfile); profiles.Add(activeProfile);
Execute.PostToUIThread(() => Execute.PostToUIThread(() =>
{ {
// Populate the UI collection // Populate the UI collection

View File

@ -0,0 +1,55 @@
using System.Linq;
using Artemis.Core.Models.Profile.Abstract;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract
{
public abstract class ProfileElementViewModel : PropertyChangedBase
{
protected ProfileElementViewModel()
{
Children = new BindableCollection<ProfileElementViewModel>();
}
public FolderViewModel Parent { get; set; }
public ProfileElement ProfileElement { get; set; }
public BindableCollection<ProfileElementViewModel> Children { get; set; }
public virtual void UpdateProfileElements()
{
// Order the children
var vmsList = Children.OrderBy(v => v.ProfileElement.Order).ToList();
for (var index = 0; index < vmsList.Count; index++)
{
var profileElementViewModel = vmsList[index];
Children.Move(Children.IndexOf(profileElementViewModel), index);
}
}
public void SetElementInFront(ProfileElementViewModel source)
{
if (source.Parent != Parent)
{
source.Parent.RemoveExistingElement(source);
Parent.AddExistingElement(source);
}
Parent.Folder.RemoveChild(source.ProfileElement);
Parent.Folder.AddChild(source.ProfileElement, ProfileElement.Order);
Parent.UpdateProfileElements();
}
public void SetElementBehind(ProfileElementViewModel source)
{
if (source.Parent != Parent)
{
source.Parent.RemoveExistingElement(source);
Parent.AddExistingElement(source);
}
Parent.Folder.RemoveChild(source.ProfileElement);
Parent.Folder.AddChild(source.ProfileElement, ProfileElement.Order + 1);
Parent.UpdateProfileElements();
}
}
}

View File

@ -0,0 +1,38 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.FolderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:FolderViewModel}}">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename" Command="{s:Action Rename}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="RenameBox" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Add new folder" Command="{s:Action AddFolder}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="CreateNewFolder" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add new layer" Command="{s:Action AddLayer}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="LayersPlus" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Folder" />
<TextBlock Text="{Binding Folder.Name}" Margin="10 0 0 0" />
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
{
/// <summary>
/// Interaction logic for FolderView.xaml
/// </summary>
public partial class FolderView : UserControl
{
public FolderView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,76 @@
using System.Linq;
using Artemis.Core.Models.Profile;
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
{
public class FolderViewModel : ProfileElementViewModel
{
public FolderViewModel(Folder folder, FolderViewModel parent)
{
Folder = folder;
Parent = parent;
ProfileElement = folder;
}
public Folder Folder { get; }
public void AddFolder()
{
Folder.AddFolder("New folder");
UpdateProfileElements();
}
public void AddLayer()
{
Folder.AddLayer("New layer");
UpdateProfileElements();
}
public void RemoveExistingElement(ProfileElementViewModel element)
{
Folder.RemoveChild(element.ProfileElement);
Children.Remove(element);
element.Parent = null;
UpdateProfileElements();
}
public void AddExistingElement(ProfileElementViewModel element)
{
Folder.AddChild(element.ProfileElement);
Children.Add(element);
element.Parent = this;
UpdateProfileElements();
}
public override void UpdateProfileElements()
{
// Ensure every child element has an up-to-date VM
if (Folder.Children != null)
{
foreach (var profileElement in Folder.Children.OrderBy(c => c.Order))
{
ProfileElementViewModel existing = null;
if (profileElement is Folder folder)
{
existing = Children.FirstOrDefault(p => p is FolderViewModel vm && vm.Folder == folder);
if (existing == null)
Children.Add(new FolderViewModel(folder, this));
}
else if (profileElement is Layer layer)
{
existing = Children.FirstOrDefault(p => p is LayerViewModel vm && vm.Layer == layer);
if (existing == null)
Children.Add(new LayerViewModel(layer, this));
}
existing?.UpdateProfileElements();
}
}
base.UpdateProfileElements();
}
}
}

View File

@ -0,0 +1,27 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.LayerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:LayerViewModel}}">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename" Command="{s:Action Rename}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="RenameBox" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Layers" />
<TextBlock Text="{Binding Layer.Name}" Margin="10 0 0 0" />
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
using Artemis.Core.Models.Profile;
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
{
public class LayerViewModel : ProfileElementViewModel
{
public LayerViewModel(Layer layer, FolderViewModel parent)
{
Layer = layer;
Parent = parent;
ProfileElement = layer;
}
public Layer Layer { get; }
}
}

View File

@ -0,0 +1,55 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.ProfileElementsView"
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:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
xmlns:models="clr-namespace:Artemis.Core.Models.Profile.Abstract;assembly=Artemis.Core"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:dd="urn:gong-wpf-dragdrop"
xmlns:profileElements="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.ProfileElements"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type profileElements:ProfileElementsViewModel}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TreeView Grid.Row="0"
ItemsSource="{Binding RootFolder.Children}"
HorizontalContentAlignment="Stretch"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type profileEditor:FolderViewModel}" ItemsSource="{Binding Children}">
<ContentControl s:View.Model="{Binding}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type profileEditor:LayerViewModel}" ItemsSource="{Binding Children}">
<ContentControl s:View.Model="{Binding}" AllowDrop="False" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
<StackPanel HorizontalAlignment="Right" Grid.Row="1" Orientation="Horizontal" Margin="8">
<Button Style="{StaticResource MaterialDesignToolButton}"
Width="30"
Padding="2 0 2 0"
materialDesign:RippleAssist.IsCentered="True"
ToolTip="Add new folder"
Command="{s:Action AddFolder}">
<materialDesign:PackIcon Kind="CreateNewFolder" />
</Button>
<Button Style="{StaticResource MaterialDesignToolButton}"
Width="30"
Padding="2 0 2 0"
materialDesign:RippleAssist.IsCentered="True"
ToolTip="Add new layer"
Command="{s:Action AddLayer}">
<materialDesign:PackIcon Kind="LayersPlus" />
</Button>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,124 @@
using System.Linq;
using System.Windows;
using Artemis.Core.Models.Profile;
using Artemis.UI.Screens.Module.ProfileEditor.ProfileElements.Abstract;
using GongSolutions.Wpf.DragDrop;
namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileElements
{
public class ProfileElementsViewModel : ProfileEditorPanelViewModel, IDropTarget
{
public ProfileElementsViewModel()
{
CreateRootFolderViewModel();
}
public FolderViewModel RootFolder { get; set; }
public void DragOver(IDropInfo dropInfo)
{
var dragDropType = GetDragDropType(dropInfo);
switch (dragDropType)
{
case DragDropType.FolderAdd:
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
dropInfo.Effects = DragDropEffects.Move;
break;
case DragDropType.FolderInsertBefore:
case DragDropType.FolderInsertAfter:
case DragDropType.LayerInsertBefore:
case DragDropType.LayerInsertAfter:
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
dropInfo.Effects = DragDropEffects.Move;
break;
}
}
public void Drop(IDropInfo dropInfo)
{
var source = (ProfileElementViewModel) dropInfo.Data;
var target = (ProfileElementViewModel) dropInfo.TargetItem;
var dragDropType = GetDragDropType(dropInfo);
switch (dragDropType)
{
case DragDropType.FolderAdd:
source.Parent.RemoveExistingElement(source);
((FolderViewModel) target).AddExistingElement(source);
break;
case DragDropType.FolderInsertBefore:
case DragDropType.LayerInsertBefore:
target.SetElementInFront(source);
break;
case DragDropType.FolderInsertAfter:
case DragDropType.LayerInsertAfter:
target.SetElementBehind(source);
break;
}
}
public void AddFolder()
{
RootFolder?.AddFolder();
}
public void AddLayer()
{
RootFolder?.AddLayer();
}
public override void OnProfileChanged()
{
CreateRootFolderViewModel();
base.OnProfileChanged();
}
private void CreateRootFolderViewModel()
{
if (!(Profile?.Children?.FirstOrDefault() is Folder folder))
{
RootFolder = null;
return;
}
RootFolder = new FolderViewModel(folder, null);
}
private DragDropType GetDragDropType(IDropInfo dropInfo)
{
var source = dropInfo.Data as ProfileElementViewModel;
var target = dropInfo.TargetItem as ProfileElementViewModel;
if (source == target)
return DragDropType.None;
if (target is FolderViewModel)
{
if (dropInfo.InsertPosition >= RelativeInsertPosition.TargetItemCenter)
return DragDropType.FolderAdd;
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
return DragDropType.FolderInsertBefore;
return DragDropType.FolderInsertAfter;
}
if (target is LayerViewModel)
{
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
return DragDropType.LayerInsertBefore;
return DragDropType.LayerInsertAfter;
}
return DragDropType.None;
}
}
public enum DragDropType
{
None,
FolderAdd,
FolderInsertBefore,
FolderInsertAfter,
LayerInsertBefore,
LayerInsertAfter
}
}

View File

@ -65,7 +65,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
private void CreateRectangleGeometry() private void CreateRectangleGeometry()
{ {
DisplayGeometry = new RectangleGeometry(new Rect(0.5, 0.5, Width - 1, Height - 1)); DisplayGeometry = new RectangleGeometry(new Rect(0.5, 0.5, Width - 1, Height - 1));
} }

View File

@ -1,12 +1,12 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.ProfileView" <UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.ProfileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization" xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}"> d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}">
<UserControl.Resources> <UserControl.Resources>
@ -36,12 +36,12 @@
</Style> </Style>
</UserControl.Resources> </UserControl.Resources>
<Grid ClipToBounds="True" <Grid ClipToBounds="True"
KeyUp="{s:Action EditorGridKeyUp}" KeyUp="{s:Action EditorGridKeyUp}"
KeyDown="{s:Action EditorGridKeyDown}" KeyDown="{s:Action EditorGridKeyDown}"
MouseWheel="{s:Action EditorGridMouseWheel}" MouseWheel="{s:Action EditorGridMouseWheel}"
MouseUp="{s:Action EditorGridMouseClick}" MouseUp="{s:Action EditorGridMouseClick}"
MouseDown="{s:Action EditorGridMouseClick}" MouseDown="{s:Action EditorGridMouseClick}"
MouseMove="{s:Action EditorGridMouseMove}"> MouseMove="{s:Action EditorGridMouseMove}">
<Grid.Background> <Grid.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute"> <VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute">
<VisualBrush.Visual> <VisualBrush.Visual>
@ -109,29 +109,29 @@
<!-- Multi-selection rectangle --> <!-- Multi-selection rectangle -->
<Path Data="{Binding SelectionRectangle}" Opacity="0" <Path Data="{Binding SelectionRectangle}" Opacity="0"
Stroke="{DynamicResource PrimaryHueLightBrush}" Stroke="{DynamicResource PrimaryHueLightBrush}"
StrokeThickness="1" StrokeThickness="1"
Name="MultiSelectionPath" Name="MultiSelectionPath"
IsHitTestVisible="False"> IsHitTestVisible="False">
<Path.Fill> <Path.Fill>
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" /> <SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
</Path.Fill> </Path.Fill>
</Path> </Path>
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Right" <StackPanel Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Right"
Margin="0, 0, 15, 15"> Margin="0, 0, 15, 15">
<Slider Margin="0,0,14,0" <Slider Margin="0,0,14,0"
Orientation="Vertical" Orientation="Vertical"
Minimum="10" Minimum="10"
Maximum="400" Maximum="400"
Height="100" Height="100"
FocusVisualStyle="{x:Null}" FocusVisualStyle="{x:Null}"
Value="{Binding PanZoomViewModel.ZoomPercentage}" Value="{Binding PanZoomViewModel.ZoomPercentage}"
Style="{StaticResource MaterialDesignDiscreteSlider}" /> Style="{StaticResource MaterialDesignDiscreteSlider}" />
<Button Command="{s:Action ResetZoomAndPan}" <Button Command="{s:Action ResetZoomAndPan}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
ToolTip="Reset zoom &amp; position"> ToolTip="Reset zoom &amp; position">
<materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" /> <materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" />
</Button> </Button>
</StackPanel> </StackPanel>
@ -140,10 +140,10 @@
<Grid Background="{StaticResource MaterialDesignPaper}" Style="{StaticResource InitializingFade}"> <Grid Background="{StaticResource MaterialDesignPaper}" Style="{StaticResource InitializingFade}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center">
Initializing LED visualization... Initializing LED visualization...
</TextBlock> </TextBlock>
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" /> <ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -7,7 +7,6 @@ using System.Windows.Media;
using Artemis.Core.Events; using Artemis.Core.Events;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.Core.Services.Storage;
using Artemis.Core.Services.Storage.Interfaces; using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Screens.Shared; using Artemis.UI.Screens.Shared;
using Artemis.UI.Screens.SurfaceEditor; using Artemis.UI.Screens.SurfaceEditor;
@ -94,8 +93,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
lock (Devices) lock (Devices)
{ {
if (IsInitializing) if (IsInitializing)
IsInitializing = Devices.Any(d => !d.AddedLeds); IsInitializing = Devices.Any(d => !d.AddedLeds);
foreach (var profileDeviceViewModel in Devices) foreach (var profileDeviceViewModel in Devices)
profileDeviceViewModel.Update(); profileDeviceViewModel.Update();
} }
@ -116,7 +115,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
#region Selection #region Selection
private MouseDragStatus _mouseDragStatus; private MouseDragStatus _mouseDragStatus;
private System.Windows.Point _mouseDragStartPoint; private Point _mouseDragStartPoint;
// ReSharper disable once UnusedMember.Global - Called from view // ReSharper disable once UnusedMember.Global - Called from view
public void EditorGridMouseClick(object sender, MouseEventArgs e) public void EditorGridMouseClick(object sender, MouseEventArgs e)
@ -124,7 +123,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
if (IsPanKeyDown()) if (IsPanKeyDown())
return; return;
var position = e.GetPosition((IInputElement)sender); var position = e.GetPosition((IInputElement) sender);
var relative = PanZoomViewModel.GetRelativeMousePosition(sender, e); var relative = PanZoomViewModel.GetRelativeMousePosition(sender, e);
if (e.LeftButton == MouseButtonState.Pressed) if (e.LeftButton == MouseButtonState.Pressed)
StartMouseDrag(position, relative); StartMouseDrag(position, relative);
@ -142,12 +141,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
return; return;
} }
var position = e.GetPosition((IInputElement)sender); var position = e.GetPosition((IInputElement) sender);
if (_mouseDragStatus == MouseDragStatus.Selecting) if (_mouseDragStatus == MouseDragStatus.Selecting)
UpdateSelection(position); UpdateSelection(position);
} }
private void StartMouseDrag(System.Windows.Point position, System.Windows.Point relative) private void StartMouseDrag(Point position, Point relative)
{ {
_mouseDragStatus = MouseDragStatus.Selecting; _mouseDragStatus = MouseDragStatus.Selecting;
_mouseDragStartPoint = position; _mouseDragStartPoint = position;
@ -156,7 +155,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
SelectionRectangle.Rect = new Rect(); SelectionRectangle.Rect = new Rect();
} }
private void StopMouseDrag(System.Windows.Point position) private void StopMouseDrag(Point position)
{ {
var selectedRect = new Rect(_mouseDragStartPoint, position); var selectedRect = new Rect(_mouseDragStartPoint, position);
// TODO: Select LEDs // TODO: Select LEDs

View File

@ -1,12 +1,12 @@
<UserControl x:Class="Artemis.UI.Screens.News.NewsView" <UserControl x:Class="Artemis.UI.Screens.News.NewsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.News" xmlns:local="clr-namespace:Artemis.UI.Screens.News"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid>
<TextBlock>Today's news: There is no news (yet)!</TextBlock> <TextBlock>Today's news: There is no news (yet)!</TextBlock>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -11,8 +11,6 @@ using Artemis.UI.Screens.News;
using Artemis.UI.Screens.Settings; using Artemis.UI.Screens.Settings;
using Artemis.UI.Screens.SurfaceEditor; using Artemis.UI.Screens.SurfaceEditor;
using Artemis.UI.Screens.Workshop; using Artemis.UI.Screens.Workshop;
using MahApps.Metro.Controls;
using MaterialDesignThemes.Wpf.Transitions;
using Stylet; using Stylet;
namespace Artemis.UI.Screens namespace Artemis.UI.Screens

View File

@ -6,15 +6,15 @@
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="213.053" d:DesignWidth="254.425" > d:DesignHeight="213.053" d:DesignWidth="254.425">
<StackPanel Margin="16"> <StackPanel Margin="16">
<TextBlock Style="{StaticResource MaterialDesignTitleTextBlock}"> <TextBlock Style="{StaticResource MaterialDesignTitleTextBlock}">
Add a new surface layout Add a new surface layout
</TextBlock> </TextBlock>
<TextBox materialDesign:HintAssist.Hint="Layout name" <TextBox materialDesign:HintAssist.Hint="Layout name"
Margin="0 8 0 16" Margin="0 8 0 16"
Style="{StaticResource MaterialDesignFloatingHintTextBox}" Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding SurfaceName, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding SurfaceName, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">

View File

@ -21,9 +21,9 @@ namespace Artemis.UI.Screens.SurfaceEditor
{ {
public class SurfaceEditorViewModel : Screen, IScreenViewModel public class SurfaceEditorViewModel : Screen, IScreenViewModel
{ {
private readonly IDeviceService _deviceService;
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IDeviceService _deviceService;
private readonly ISurfaceService _surfaceService; private readonly ISurfaceService _surfaceService;
public SurfaceEditorViewModel(ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService, IDeviceService deviceService) public SurfaceEditorViewModel(ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService, IDeviceService deviceService)
@ -52,6 +52,9 @@ namespace Artemis.UI.Screens.SurfaceEditor
get => _selectedSurface; get => _selectedSurface;
set set
{ {
if (value == null)
return;
_selectedSurface = value; _selectedSurface = value;
ApplySelectedSurfaceConfiguration(); ApplySelectedSurfaceConfiguration();
} }
@ -104,12 +107,6 @@ namespace Artemis.UI.Screens.SurfaceEditor
private void ApplySelectedSurfaceConfiguration() private void ApplySelectedSurfaceConfiguration()
{ {
if (SelectedSurface == null)
{
Execute.PostToUIThread(Devices.Clear);
return;
}
// Make sure all devices have an up-to-date VM // Make sure all devices have an up-to-date VM
foreach (var surfaceDeviceConfiguration in SelectedSurface.Devices) foreach (var surfaceDeviceConfiguration in SelectedSurface.Devices)
{ {

View File

@ -59,7 +59,7 @@
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
</Grid> </Grid>
<!-- Selection rectangle --> <!-- Selection rectangle -->
<Rectangle Width="Auto" Height="Auto" StrokeThickness="2"> <Rectangle Width="Auto" Height="Auto" StrokeThickness="2">
<Rectangle.Stroke> <Rectangle.Stroke>

View File

@ -1,12 +1,12 @@
<UserControl x:Class="Artemis.UI.Screens.Workshop.WorkshopView" <UserControl x:Class="Artemis.UI.Screens.Workshop.WorkshopView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Workshop" xmlns:local="clr-namespace:Artemis.UI.Screens.Workshop"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid>
<TextBlock>Work work!</TextBlock> <TextBlock>Work work!</TextBlock>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -5,6 +5,7 @@
<package id="Dragablz" version="0.0.3.203" targetFramework="net472" /> <package id="Dragablz" version="0.0.3.203" targetFramework="net472" />
<package id="FluentValidation" version="8.5.0" targetFramework="net472" /> <package id="FluentValidation" version="8.5.0" targetFramework="net472" />
<package id="Fody" version="6.0.5" targetFramework="net472" developmentDependency="true" /> <package id="Fody" version="6.0.5" targetFramework="net472" developmentDependency="true" />
<package id="gong-wpf-dragdrop" version="2.1.0" targetFramework="net472" />
<package id="Humanizer.Core" version="2.6.2" targetFramework="net461" /> <package id="Humanizer.Core" version="2.6.2" targetFramework="net461" />
<package id="MahApps.Metro" version="1.6.5" targetFramework="net472" /> <package id="MahApps.Metro" version="1.6.5" targetFramework="net472" />
<package id="MaterialDesignColors" version="1.2.0" targetFramework="net472" /> <package id="MaterialDesignColors" version="1.2.0" targetFramework="net472" />