mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Profile editor - Moved files
This commit is contained in:
1 parent
f359256ede
commit
75e2fb1689
86 files changed
+199
-215
No files matched your search
@@ -0,0 +1,72 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.ProfileTreeView"
|
||||
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:dd="urn:gong-wpf-dragdrop"
|
||||
xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree"
|
||||
xmlns:treeItem="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:profileTree1="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree"
|
||||
xmlns:treeItem1="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type profileTree1:ProfileTreeViewModel}}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="10 5 0 -4">
|
||||
Profile elements
|
||||
</TextBlock>
|
||||
<Separator Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||
</StackPanel>
|
||||
|
||||
<TreeView Grid.Row="1"
|
||||
ItemsSource="{Binding RootFolder.Children}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.DropHandler="{Binding}">
|
||||
<b:Interaction.Behaviors>
|
||||
<behaviors:TreeViewSelectionBehavior ExpandSelected="True" SelectedItem="{Binding SelectedTreeItem}" />
|
||||
</b:Interaction.Behaviors>
|
||||
<TreeView.Resources>
|
||||
<HierarchicalDataTemplate DataType="{x:Type treeItem1:FolderViewModel}" ItemsSource="{Binding Children}">
|
||||
<ContentControl s:View.Model="{Binding}" />
|
||||
</HierarchicalDataTemplate>
|
||||
<!-- TODO: Ensure this item source is required -->
|
||||
<HierarchicalDataTemplate DataType="{x:Type treeItem1:LayerViewModel}" ItemsSource="{Binding Children}">
|
||||
<ContentControl s:View.Model="{Binding}" />
|
||||
</HierarchicalDataTemplate>
|
||||
</TreeView.Resources>
|
||||
</TreeView>
|
||||
|
||||
<StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Margin="8">
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Padding="2 0 2 0"
|
||||
Width="30"
|
||||
Height="30"
|
||||
materialDesign:RippleAssist.IsCentered="True"
|
||||
ToolTip="Add new folder to root"
|
||||
Command="{s:Action AddFolder}">
|
||||
<materialDesign:PackIcon Kind="CreateNewFolder" Width="15" />
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Padding="2 0 2 0"
|
||||
materialDesign:RippleAssist.IsCentered="True"
|
||||
ToolTip="Add new layer to root"
|
||||
Command="{s:Action AddLayer}">
|
||||
<materialDesign:PackIcon Kind="LayersPlus" Width="15" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem;
|
||||
using Artemis.UI.Shared.Events;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using GongSolutions.Wpf.DragDrop;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
{
|
||||
public class ProfileTreeViewModel : ProfileEditorPanelViewModel, IDropTarget
|
||||
{
|
||||
private readonly IFolderVmFactory _folderVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private TreeItemViewModel _selectedTreeItem;
|
||||
private bool _updatingTree;
|
||||
private FolderViewModel _rootFolder;
|
||||
|
||||
public ProfileTreeViewModel(IProfileEditorService profileEditorService, IFolderVmFactory folderVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_folderVmFactory = folderVmFactory;
|
||||
}
|
||||
|
||||
public FolderViewModel RootFolder
|
||||
{
|
||||
get => _rootFolder;
|
||||
set => SetAndNotify(ref _rootFolder, value);
|
||||
}
|
||||
|
||||
public TreeItemViewModel SelectedTreeItem
|
||||
{
|
||||
get => _selectedTreeItem;
|
||||
set
|
||||
{
|
||||
if (_updatingTree) return;
|
||||
if (!SetAndNotify(ref _selectedTreeItem, value)) return;
|
||||
|
||||
if (value != null && value.ProfileElement is RenderProfileElement renderElement)
|
||||
_profileEditorService.ChangeSelectedProfileElement(renderElement);
|
||||
else
|
||||
_profileEditorService.ChangeSelectedProfileElement(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void DragOver(IDropInfo dropInfo)
|
||||
{
|
||||
var dragDropType = GetDragDropType(dropInfo);
|
||||
|
||||
switch (dragDropType)
|
||||
{
|
||||
case DragDropType.Add:
|
||||
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
|
||||
dropInfo.Effects = DragDropEffects.Move;
|
||||
break;
|
||||
case DragDropType.InsertBefore:
|
||||
case DragDropType.InsertAfter:
|
||||
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
|
||||
dropInfo.Effects = DragDropEffects.Move;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Drop(IDropInfo dropInfo)
|
||||
{
|
||||
var source = (TreeItemViewModel) dropInfo.Data;
|
||||
var target = (TreeItemViewModel) dropInfo.TargetItem;
|
||||
|
||||
var dragDropType = GetDragDropType(dropInfo);
|
||||
switch (dragDropType)
|
||||
{
|
||||
case DragDropType.Add:
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
target.AddExistingElement(source);
|
||||
break;
|
||||
case DragDropType.InsertBefore:
|
||||
target.SetElementInFront(source);
|
||||
break;
|
||||
case DragDropType.InsertAfter:
|
||||
target.SetElementBehind(source);
|
||||
break;
|
||||
}
|
||||
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void AddFolder()
|
||||
{
|
||||
RootFolder?.AddFolder();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void AddLayer()
|
||||
{
|
||||
RootFolder?.AddLayer();
|
||||
}
|
||||
|
||||
private void CreateRootFolderViewModel()
|
||||
{
|
||||
_updatingTree = true;
|
||||
var firstChild = _profileEditorService.SelectedProfile?.Children?.FirstOrDefault();
|
||||
if (!(firstChild is Folder folder))
|
||||
{
|
||||
RootFolder = null;
|
||||
return;
|
||||
}
|
||||
|
||||
RootFolder?.Dispose();
|
||||
RootFolder = _folderVmFactory.Create(folder);
|
||||
_updatingTree = false;
|
||||
|
||||
// Auto-select the first layer
|
||||
if (_profileEditorService.SelectedProfile != null && SelectedTreeItem == null)
|
||||
{
|
||||
if (_profileEditorService.SelectedProfile.GetRootFolder().Children.FirstOrDefault() is RenderProfileElement firstElement)
|
||||
Execute.PostToUIThread(() => _profileEditorService.ChangeSelectedProfileElement(firstElement));
|
||||
}
|
||||
}
|
||||
|
||||
private static DragDropType GetDragDropType(IDropInfo dropInfo)
|
||||
{
|
||||
var source = (TreeItemViewModel) dropInfo.Data;
|
||||
var target = (TreeItemViewModel) dropInfo.TargetItem;
|
||||
if (source == target)
|
||||
return DragDropType.None;
|
||||
|
||||
var parent = target;
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent == source)
|
||||
return DragDropType.None;
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
switch (dropInfo.InsertPosition)
|
||||
{
|
||||
case RelativeInsertPosition.AfterTargetItem | RelativeInsertPosition.TargetItemCenter:
|
||||
case RelativeInsertPosition.BeforeTargetItem | RelativeInsertPosition.TargetItemCenter:
|
||||
return target.SupportsChildren ? DragDropType.Add : DragDropType.None;
|
||||
case RelativeInsertPosition.BeforeTargetItem:
|
||||
return DragDropType.InsertBefore;
|
||||
case RelativeInsertPosition.AfterTargetItem:
|
||||
return DragDropType.InsertAfter;
|
||||
default:
|
||||
return DragDropType.None;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_profileEditorService.ProfileSelected += OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||
CreateRootFolderViewModel();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.ProfileSelected -= OnProfileSelected;
|
||||
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
|
||||
|
||||
RootFolder?.Dispose();
|
||||
RootFolder = null;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void OnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.RenderProfileElement == SelectedTreeItem?.ProfileElement)
|
||||
return;
|
||||
|
||||
if (RootFolder == null)
|
||||
{
|
||||
CreateRootFolderViewModel();
|
||||
return;
|
||||
}
|
||||
|
||||
_updatingTree = true;
|
||||
RootFolder.UpdateProfileElements();
|
||||
_updatingTree = false;
|
||||
if (e.RenderProfileElement == null)
|
||||
SelectedTreeItem = null;
|
||||
else
|
||||
{
|
||||
var match = RootFolder.GetAllChildren().FirstOrDefault(vm => vm.ProfileElement == e.RenderProfileElement);
|
||||
if (match != null)
|
||||
SelectedTreeItem = match;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProfileSelected(object sender, EventArgs e)
|
||||
{
|
||||
CreateRootFolderViewModel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum DragDropType
|
||||
{
|
||||
None,
|
||||
Add,
|
||||
InsertBefore,
|
||||
InsertAfter
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem.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:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:treeItem="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
xmlns:treeItem1="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type treeItem1:FolderViewModel}}">
|
||||
<!-- Capture clicks on full tree view item -->
|
||||
<StackPanel Margin="-10" Background="Transparent">
|
||||
<StackPanel.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Rename" Command="{s:Action RenameElement}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="RenameBox" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Delete" Command="{s:Action DeleteElement}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="TrashCan" />
|
||||
</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>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon Grid.Column="0"
|
||||
Kind="Folder"
|
||||
Visibility="{Binding IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" />
|
||||
<materialDesign:PackIcon Grid.Column="0"
|
||||
Kind="FolderOpen"
|
||||
Visibility="{Binding IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding ProfileElement.Name}" Margin="10 0 0 0" VerticalAlignment="Center" />
|
||||
<ToggleButton Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignFlatToggleButton}"
|
||||
ToolTip="Toggle enabled state"
|
||||
Width="18"
|
||||
Height="18"
|
||||
IsChecked="{Binding ProfileElement.Enabled}"
|
||||
Command="{s:Action EnableToggled}"
|
||||
VerticalAlignment="Center" Padding="-25">
|
||||
<materialDesign:PackIcon Kind="Eye" Height="13" Width="13" />
|
||||
</ToggleButton>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,46 @@
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
{
|
||||
public class FolderViewModel : TreeItemViewModel
|
||||
{
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var treeItemViewModel in Children)
|
||||
treeItemViewModel.Dispose();
|
||||
Children.Clear();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
// I hate this about DI, oh well
|
||||
public FolderViewModel(ProfileElement folder,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService,
|
||||
IRenderElementService renderElementService,
|
||||
IFolderVmFactory folderVmFactory,
|
||||
ILayerVmFactory layerVmFactory) :
|
||||
base(null, folder, profileEditorService, dialogService, renderElementService, folderVmFactory, layerVmFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public FolderViewModel(TreeItemViewModel parent,
|
||||
ProfileElement folder,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService,
|
||||
IRenderElementService renderElementService,
|
||||
IFolderVmFactory folderVmFactory,
|
||||
ILayerVmFactory layerVmFactory) :
|
||||
base(parent, folder, profileEditorService, dialogService, renderElementService, folderVmFactory, layerVmFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool SupportsChildren => true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem.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:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:treeItem="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
xmlns:treeItem1="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type treeItem1:LayerViewModel}}">
|
||||
<!-- Capture clicks on full tree view item -->
|
||||
<StackPanel Margin="-10" Background="Transparent">
|
||||
<StackPanel.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Rename" Command="{s:Action RenameElement}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="RenameBox" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Delete" Command="{s:Action DeleteElement}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="TrashCan" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</StackPanel.ContextMenu>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon Grid.Column="0" Kind="Layers" Width="16" VerticalAlignment="Center"/>
|
||||
<materialDesign:PackIcon Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Kind="{Binding Layer.LayerBrush.Descriptor.Icon}"
|
||||
Width="16"
|
||||
Margin="5 0 0 0"
|
||||
ToolTip="{Binding Layer.LayerBrush.Descriptor.DisplayName, Mode=OneWay}"
|
||||
Visibility="{Binding ShowIcons, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||
Background="Transparent" />
|
||||
<TextBlock Grid.Column="2" Text="{Binding Layer.Name}" VerticalAlignment="Center" Margin="5 0 0 0" />
|
||||
<ToggleButton Grid.Column="3"
|
||||
Style="{StaticResource MaterialDesignFlatToggleButton}"
|
||||
ToolTip="Toggle enabled state"
|
||||
Width="18"
|
||||
Height="18"
|
||||
IsChecked="{Binding ProfileElement.Enabled}"
|
||||
Command="{s:Action EnableToggled}"
|
||||
VerticalAlignment="Center" Padding="-25">
|
||||
<materialDesign:PackIcon Kind="Eye" Height="13" Width="13" />
|
||||
</ToggleButton>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,25 @@
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
{
|
||||
public class LayerViewModel : TreeItemViewModel
|
||||
{
|
||||
public LayerViewModel(TreeItemViewModel parent,
|
||||
ProfileElement folder,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService,
|
||||
IRenderElementService renderElementService,
|
||||
IFolderVmFactory folderVmFactory,
|
||||
ILayerVmFactory layerVmFactory) :
|
||||
base(parent, folder, profileEditorService, dialogService, renderElementService, folderVmFactory, layerVmFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public Layer Layer => ProfileElement as Layer;
|
||||
public bool ShowIcons => Layer?.LayerBrush != null;
|
||||
public override bool SupportsChildren => false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Dialogs;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
{
|
||||
public abstract class TreeItemViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IFolderVmFactory _folderVmFactory;
|
||||
private readonly ILayerVmFactory _layerVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IRenderElementService _renderElementService;
|
||||
private TreeItemViewModel _parent;
|
||||
private ProfileElement _profileElement;
|
||||
|
||||
protected TreeItemViewModel(TreeItemViewModel parent,
|
||||
ProfileElement profileElement,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService,
|
||||
IRenderElementService renderElementService,
|
||||
IFolderVmFactory folderVmFactory,
|
||||
ILayerVmFactory layerVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dialogService = dialogService;
|
||||
_renderElementService = renderElementService;
|
||||
_folderVmFactory = folderVmFactory;
|
||||
_layerVmFactory = layerVmFactory;
|
||||
|
||||
Parent = parent;
|
||||
ProfileElement = profileElement;
|
||||
|
||||
Children = new BindableCollection<TreeItemViewModel>();
|
||||
|
||||
ProfileElement.ChildAdded += ProfileElementOnChildAdded;
|
||||
ProfileElement.ChildRemoved += ProfileElementOnChildRemoved;
|
||||
|
||||
UpdateProfileElements();
|
||||
}
|
||||
|
||||
public TreeItemViewModel Parent
|
||||
{
|
||||
get => _parent;
|
||||
set => SetAndNotify(ref _parent, value);
|
||||
}
|
||||
|
||||
public ProfileElement ProfileElement
|
||||
{
|
||||
get => _profileElement;
|
||||
set => SetAndNotify(ref _profileElement, value);
|
||||
}
|
||||
|
||||
public BindableCollection<TreeItemViewModel> Children { get; }
|
||||
|
||||
public abstract bool SupportsChildren { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ProfileElement.ChildAdded -= ProfileElementOnChildAdded;
|
||||
ProfileElement.ChildRemoved -= ProfileElementOnChildRemoved;
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public List<TreeItemViewModel> GetAllChildren()
|
||||
{
|
||||
var children = new List<TreeItemViewModel>();
|
||||
foreach (var childFolder in Children)
|
||||
{
|
||||
// Add all children in this element
|
||||
children.Add(childFolder);
|
||||
// Add all children of children inside this element
|
||||
children.AddRange(childFolder.GetAllChildren());
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
public void SetElementInFront(TreeItemViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.ProfileElement.RemoveChild(source.ProfileElement);
|
||||
Parent.ProfileElement.AddChild(source.ProfileElement, ProfileElement.Order);
|
||||
}
|
||||
|
||||
public void SetElementBehind(TreeItemViewModel source)
|
||||
{
|
||||
if (source.Parent != Parent)
|
||||
{
|
||||
source.Parent.RemoveExistingElement(source);
|
||||
Parent.AddExistingElement(source);
|
||||
}
|
||||
|
||||
Parent.ProfileElement.RemoveChild(source.ProfileElement);
|
||||
Parent.ProfileElement.AddChild(source.ProfileElement, ProfileElement.Order + 1);
|
||||
}
|
||||
|
||||
public void RemoveExistingElement(TreeItemViewModel treeItem)
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot remove a child from a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.RemoveChild(treeItem.ProfileElement);
|
||||
Children.Remove(treeItem);
|
||||
treeItem.Parent = null;
|
||||
treeItem.Dispose();
|
||||
}
|
||||
|
||||
public void AddExistingElement(TreeItemViewModel treeItem)
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a child to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.AddChild(treeItem.ProfileElement);
|
||||
Children.Add(treeItem);
|
||||
treeItem.Parent = this;
|
||||
}
|
||||
|
||||
public void AddFolder()
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a folder to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
ProfileElement.AddChild(new Folder(ProfileElement.Profile, ProfileElement, "New folder"));
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
|
||||
public void AddLayer()
|
||||
{
|
||||
if (!SupportsChildren)
|
||||
throw new ArtemisUIException("Cannot add a layer to a profile element of type " + ProfileElement.GetType().Name);
|
||||
|
||||
_renderElementService.CreateLayer(ProfileElement.Profile, ProfileElement, "New layer");
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public async Task RenameElement()
|
||||
{
|
||||
var result = await _dialogService.ShowDialog<RenameViewModel>(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{"subject", ProfileElement is Folder ? "folder" : "layer"},
|
||||
{"currentName", ProfileElement.Name}
|
||||
}
|
||||
);
|
||||
if (result is string newName)
|
||||
{
|
||||
ProfileElement.Name = newName;
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public async Task DeleteElement()
|
||||
{
|
||||
var result = await _dialogService.ShowConfirmDialog(
|
||||
"Delete profile element",
|
||||
"Are you sure you want to delete this element? This cannot be undone."
|
||||
);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
// Farewell, cruel world
|
||||
var parent = Parent;
|
||||
ProfileElement.Parent?.RemoveChild(ProfileElement);
|
||||
parent.RemoveExistingElement(this);
|
||||
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
|
||||
public void UpdateProfileElements()
|
||||
{
|
||||
// Order the children
|
||||
var vmsList = Children.OrderBy(v => v.ProfileElement.Order).ToList();
|
||||
for (var index = 0; index < vmsList.Count; index++)
|
||||
{
|
||||
var profileElementViewModel = vmsList[index];
|
||||
Children.Move(Children.IndexOf(profileElementViewModel), index);
|
||||
}
|
||||
|
||||
// Ensure every child element has an up-to-date VM
|
||||
if (ProfileElement.Children == null)
|
||||
return;
|
||||
|
||||
var newChildren = new List<TreeItemViewModel>();
|
||||
foreach (var profileElement in ProfileElement.Children.OrderBy(c => c.Order))
|
||||
{
|
||||
if (profileElement is Folder folder)
|
||||
{
|
||||
if (Children.FirstOrDefault(p => p is FolderViewModel vm && vm.ProfileElement == folder) == null)
|
||||
newChildren.Add(_folderVmFactory.Create((FolderViewModel) this, folder));
|
||||
}
|
||||
else if (profileElement is Layer layer)
|
||||
{
|
||||
if (Children.FirstOrDefault(p => p is LayerViewModel vm && vm.ProfileElement == layer) == null)
|
||||
newChildren.Add(_layerVmFactory.Create((FolderViewModel) this, layer));
|
||||
}
|
||||
}
|
||||
|
||||
if (!newChildren.Any())
|
||||
return;
|
||||
|
||||
// Add the new children in one call, prevent extra UI events
|
||||
Children.AddRange(newChildren);
|
||||
foreach (var treeItemViewModel in newChildren)
|
||||
treeItemViewModel.UpdateProfileElements();
|
||||
}
|
||||
|
||||
public void EnableToggled()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileElementOnChildRemoved(object sender, EventArgs e)
|
||||
{
|
||||
UpdateProfileElements();
|
||||
}
|
||||
|
||||
private void ProfileElementOnChildAdded(object sender, EventArgs e)
|
||||
{
|
||||
UpdateProfileElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user