mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-31 09:43:46 +00:00
Sidebar - Added profile reordering and moving to different categories
This commit is contained in:
parent
cd97ed420c
commit
bcd03becc7
2
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
2
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
@ -55,7 +55,7 @@
|
|||||||
<entry key="Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Sidebar/SidebarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Sidebar/SidebarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/SurfaceEditor/ListDeviceView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/SurfaceEditor/ListDeviceView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
|||||||
@ -98,7 +98,10 @@ namespace Artemis.Core
|
|||||||
configuration.Category.RemoveProfileConfiguration(configuration);
|
configuration.Category.RemoveProfileConfiguration(configuration);
|
||||||
|
|
||||||
if (targetIndex != null)
|
if (targetIndex != null)
|
||||||
_profileConfigurations.Insert(Math.Clamp(targetIndex.Value, 0, _profileConfigurations.Count), configuration);
|
{
|
||||||
|
targetIndex = Math.Clamp(targetIndex.Value, 0, _profileConfigurations.Count);
|
||||||
|
_profileConfigurations.Insert(targetIndex.Value, configuration);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_profileConfigurations.Add(configuration);
|
_profileConfigurations.Add(configuration);
|
||||||
configuration.Category = this;
|
configuration.Category = this;
|
||||||
@ -116,7 +119,8 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
internal void RemoveProfileConfiguration(ProfileConfiguration configuration)
|
internal void RemoveProfileConfiguration(ProfileConfiguration configuration)
|
||||||
{
|
{
|
||||||
if (!_profileConfigurations.Remove(configuration)) return;
|
if (!_profileConfigurations.Remove(configuration))
|
||||||
|
return;
|
||||||
|
|
||||||
for (int index = 0; index < _profileConfigurations.Count; index++)
|
for (int index = 0; index < _profileConfigurations.Count; index++)
|
||||||
_profileConfigurations[index].Order = index;
|
_profileConfigurations[index].Order = index;
|
||||||
|
|||||||
@ -90,7 +90,9 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid RowDefinitions="*,Auto">
|
<Grid RowDefinitions="*,Auto">
|
||||||
<TreeView Name="ProfileTreeView" Classes="no-right-margin draggable" Items="{CompiledBinding Children}" SelectedItem="{CompiledBinding SelectedChild}"
|
<TreeView Name="ProfileTreeView" Classes="no-right-margin draggable"
|
||||||
|
Items="{CompiledBinding Children}"
|
||||||
|
SelectedItem="{CompiledBinding SelectedChild}"
|
||||||
SelectionChanged="ProfileTreeView_OnSelectionChanged">
|
SelectionChanged="ProfileTreeView_OnSelectionChanged">
|
||||||
<TreeView.Styles>
|
<TreeView.Styles>
|
||||||
<Style Selector="TreeViewItem">
|
<Style Selector="TreeViewItem">
|
||||||
|
|||||||
@ -0,0 +1,124 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Generators;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
using Avalonia.Xaml.Interactions.DragAndDrop;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Sidebar.Behaviors;
|
||||||
|
|
||||||
|
public class SidebarCategoryViewDropHandler : DropHandlerBase
|
||||||
|
{
|
||||||
|
private bool Validate(ListBox listBox, DragEventArgs e, object? sourceContext, object? targetContext, bool bExecute)
|
||||||
|
{
|
||||||
|
if (sourceContext is not SidebarProfileConfigurationViewModel sourceItem || targetContext is not SidebarCategoryViewModel vm ||
|
||||||
|
listBox.GetVisualAt(e.GetPosition(listBox)) is not IControl targetControl)
|
||||||
|
return false;
|
||||||
|
if (e.DragEffects != DragDropEffects.Move)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SidebarProfileConfigurationViewModel? targetItem = targetControl.DataContext as SidebarProfileConfigurationViewModel;
|
||||||
|
ListBoxItem? targetVisual = null;
|
||||||
|
bool before = true;
|
||||||
|
if (targetItem != null)
|
||||||
|
{
|
||||||
|
Point position = e.GetPosition(listBox);
|
||||||
|
targetVisual = listBox.GetVisualAt(position).FindAncestorOfType<ListBoxItem>();
|
||||||
|
if (targetVisual != null)
|
||||||
|
{
|
||||||
|
Point positionInTarget = e.GetPosition(targetVisual);
|
||||||
|
if (positionInTarget.Y > (targetVisual.Bounds.Height / 2))
|
||||||
|
before = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ItemContainerInfo? item in listBox.ItemContainerGenerator.Containers)
|
||||||
|
SetDraggingPseudoClasses(item.ContainerControl, false, false);
|
||||||
|
|
||||||
|
if (bExecute)
|
||||||
|
{
|
||||||
|
if (targetItem != null)
|
||||||
|
{
|
||||||
|
int index = vm.ProfileConfigurations.IndexOf(targetItem);
|
||||||
|
if (!before)
|
||||||
|
index++;
|
||||||
|
vm.AddProfileConfiguration(sourceItem.ProfileConfiguration, index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vm.AddProfileConfiguration(sourceItem.ProfileConfiguration, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (targetVisual != null)
|
||||||
|
{
|
||||||
|
SetDraggingPseudoClasses(targetVisual, true, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Validate(object? sender, DragEventArgs e, object? sourceContext, object? targetContext, object? state)
|
||||||
|
{
|
||||||
|
if (sender is ItemsControl itemsControl)
|
||||||
|
{
|
||||||
|
foreach (ItemContainerInfo? item in itemsControl.ItemContainerGenerator.Containers)
|
||||||
|
SetDraggingPseudoClasses(item.ContainerControl, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Source is IControl && sender is ListBox listBox)
|
||||||
|
{
|
||||||
|
return Validate(listBox, e, sourceContext, targetContext, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute(object? sender, DragEventArgs e, object? sourceContext, object? targetContext, object? state)
|
||||||
|
{
|
||||||
|
if (sender is ItemsControl itemsControl)
|
||||||
|
{
|
||||||
|
foreach (ItemContainerInfo? item in itemsControl.ItemContainerGenerator.Containers)
|
||||||
|
SetDraggingPseudoClasses(item.ContainerControl, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Source is IControl && sender is ListBox listBox)
|
||||||
|
{
|
||||||
|
return Validate(listBox, e, sourceContext, targetContext, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetDraggingPseudoClasses(IControl control, bool dragging, bool before)
|
||||||
|
{
|
||||||
|
if (!dragging)
|
||||||
|
{
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-before");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-after");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-into");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((IPseudoClasses) control.Classes).Add(":dragging");
|
||||||
|
if (before)
|
||||||
|
{
|
||||||
|
((IPseudoClasses) control.Classes).Add(":dragging-before");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-after");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-into");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-before");
|
||||||
|
((IPseudoClasses) control.Classes).Add(":dragging-after");
|
||||||
|
((IPseudoClasses) control.Classes).Remove(":dragging-into");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,9 +4,17 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||||
|
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
|
||||||
|
xmlns:idd="clr-namespace:Avalonia.Xaml.Interactions.DragAndDrop;assembly=Avalonia.Xaml.Interactions"
|
||||||
|
xmlns:sb="clr-namespace:Artemis.UI.Screens.Sidebar.Behaviors"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
xmlns:b="clr-namespace:Artemis.UI.Behaviors"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarCategoryView"
|
x:Class="Artemis.UI.Screens.Sidebar.SidebarCategoryView"
|
||||||
x:DataType="local:SidebarCategoryViewModel">
|
x:DataType="local:SidebarCategoryViewModel">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:ColorOpacityConverter x:Key="ColorOpacityConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector=":is(Button).category-button">
|
<Style Selector=":is(Button).category-button">
|
||||||
<Setter Property="IsVisible" Value="False" />
|
<Setter Property="IsVisible" Value="False" />
|
||||||
@ -28,17 +36,66 @@
|
|||||||
<Setter Property="Opacity" Value="1" />
|
<Setter Property="Opacity" Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector=".sidebar-listbox > ListBoxItem">
|
<Style Selector=".sidebar-listbox > ListBoxItem">
|
||||||
<Setter Property="Padding" Value="6 0"/>
|
<Setter Property="Padding" Value="6 0" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Dragging -->
|
||||||
|
<Style Selector="ListBox.sidebar-listbox">
|
||||||
|
<Style.Resources>
|
||||||
|
<sb:SidebarCategoryViewDropHandler x:Key="SidebarCategoryViewDropHandler" />
|
||||||
|
</Style.Resources>
|
||||||
|
<Setter Property="(i:Interaction.Behaviors)">
|
||||||
|
<i:BehaviorCollectionTemplate>
|
||||||
|
<i:BehaviorCollection>
|
||||||
|
<idd:ContextDropBehavior Handler="{StaticResource SidebarCategoryViewDropHandler}" />
|
||||||
|
</i:BehaviorCollection>
|
||||||
|
</i:BehaviorCollectionTemplate>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBox.sidebar-listbox ListBoxItem">
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="(i:Interaction.Behaviors)">
|
||||||
|
<i:BehaviorCollectionTemplate>
|
||||||
|
<i:BehaviorCollection>
|
||||||
|
<b:SimpleContextDragBehavior />
|
||||||
|
</i:BehaviorCollection>
|
||||||
|
</i:BehaviorCollectionTemplate>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBox.sidebar-listbox ListBoxItem:dragging-before">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>
|
||||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,30">
|
||||||
|
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.0" />
|
||||||
|
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.05" />
|
||||||
|
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.05" />
|
||||||
|
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.25" />
|
||||||
|
</LinearGradientBrush>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBox.sidebar-listbox ListBoxItem:dragging-after">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>
|
||||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,32">
|
||||||
|
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.75" />
|
||||||
|
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.95" />
|
||||||
|
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.95" />
|
||||||
|
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="1" />
|
||||||
|
</LinearGradientBrush>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*">
|
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*">
|
||||||
<Grid Grid.Row="0" Background="Transparent" Margin="0 0 6 0" ColumnDefinitions="Auto,*,Auto,Auto,Auto,Auto">
|
<Grid Grid.Row="0" Background="Transparent" Margin="0 0 6 0" ColumnDefinitions="Auto,*,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !IsCollapsed}"
|
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !IsCollapsed}"
|
||||||
Kind="ChevronUp"
|
Kind="ChevronUp"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="5 0"
|
Margin="5 0"
|
||||||
PointerPressed="Title_OnPointerPressed"
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
Background="Transparent">
|
Background="Transparent">
|
||||||
<avalonia:MaterialIcon.Transitions>
|
<avalonia:MaterialIcon.Transitions>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
@ -56,7 +113,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{CompiledBinding ProfileCategory.Name, FallbackValue='Profile name'}"
|
Text="{CompiledBinding ProfileCategory.Name, FallbackValue='Profile name'}"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
PointerPressed="Title_OnPointerPressed"
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
Background="Transparent">
|
Background="Transparent">
|
||||||
<TextBlock.Transitions>
|
<TextBlock.Transitions>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
@ -107,7 +164,8 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Grid.Row="1">
|
<Border Grid.Row="1">
|
||||||
<ListBox Classes="sidebar-listbox"
|
<ListBox Name="SidebarListBox"
|
||||||
|
Classes="sidebar-listbox"
|
||||||
Items="{CompiledBinding ProfileConfigurations}"
|
Items="{CompiledBinding ProfileConfigurations}"
|
||||||
SelectedItem="{CompiledBinding SelectedProfileConfiguration}"
|
SelectedItem="{CompiledBinding SelectedProfileConfiguration}"
|
||||||
MinHeight="10"
|
MinHeight="10"
|
||||||
|
|||||||
@ -1,15 +1,34 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Layout;
|
||||||
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Sidebar
|
namespace Artemis.UI.Screens.Sidebar
|
||||||
{
|
{
|
||||||
public class SidebarCategoryView : ReactiveUserControl<SidebarCategoryViewModel>
|
public class SidebarCategoryView : ReactiveUserControl<SidebarCategoryViewModel>
|
||||||
{
|
{
|
||||||
|
private static Image? _dragAdorner;
|
||||||
|
private Point _dragStartPosition;
|
||||||
|
private Point _elementDragOffset;
|
||||||
|
private ListBox _listBox;
|
||||||
|
|
||||||
public SidebarCategoryView()
|
public SidebarCategoryView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_listBox = this.Get<ListBox>("SidebarListBox");
|
||||||
|
|
||||||
|
AddHandler(DragDrop.DragEnterEvent, HandleDragEnterEvent, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
|
AddHandler(DragDrop.DragOverEvent, HandleDragOver, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
|
AddHandler(PointerEnterEvent, HandlePointerEnter, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
@ -17,9 +36,104 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Title_OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel?.ToggleCollapsed.Execute().Subscribe();
|
if (e.InitialPressMouseButton == MouseButton.Left)
|
||||||
|
ViewModel?.ToggleCollapsed.Execute().Subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Dragging
|
||||||
|
|
||||||
|
private void HandlePointerEnter(object? sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
DisposeDragAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDragEnterEvent(object? sender, DragEventArgs e)
|
||||||
|
{
|
||||||
|
CreateDragAdorner(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateDragAdorner(DragEventArgs e)
|
||||||
|
{
|
||||||
|
if (_dragAdorner != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e.Source is not Control c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the list box item that raised the event
|
||||||
|
ListBoxItem? container = c.FindLogicalAncestorOfType<ListBoxItem>();
|
||||||
|
if (container == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Take a snapshot of said tree view item and add it as an adorner
|
||||||
|
ITransform? originalTransform = container.RenderTransform;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_dragStartPosition = e.GetPosition(this.FindAncestorOfType<Window>());
|
||||||
|
_elementDragOffset = e.GetPosition(container);
|
||||||
|
|
||||||
|
RenderTargetBitmap renderTarget = new(new PixelSize((int) container.Bounds.Width, (int) container.Bounds.Height));
|
||||||
|
container.RenderTransform = new TranslateTransform(container.Bounds.X * -1, container.Bounds.Y * -1);
|
||||||
|
renderTarget.Render(container);
|
||||||
|
_dragAdorner = new Image
|
||||||
|
{
|
||||||
|
Source = renderTarget,
|
||||||
|
VerticalAlignment = VerticalAlignment.Top,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
|
Stretch = Stretch.None,
|
||||||
|
IsHitTestVisible = false
|
||||||
|
};
|
||||||
|
AdornerLayer.GetAdornerLayer(this)!.Children.Add(_dragAdorner);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
container.RenderTransform = originalTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDragOver(object? sender, DragEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateDragAdorner(e.GetPosition(this.FindAncestorOfType<Window>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleLeaveEvent(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// If there is currently an adorner, dispose of it
|
||||||
|
DisposeDragAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDrop(object? sender, DragEventArgs e)
|
||||||
|
{
|
||||||
|
// If there is currently an adorner, dispose of it
|
||||||
|
DisposeDragAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposeDragAdorner()
|
||||||
|
{
|
||||||
|
if (_dragAdorner == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AdornerLayer.GetAdornerLayer(this)!.Children.Remove(_dragAdorner);
|
||||||
|
(_dragAdorner.Source as RenderTargetBitmap)?.Dispose();
|
||||||
|
_dragAdorner = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDragAdorner(Point position)
|
||||||
|
{
|
||||||
|
if (_dragAdorner == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dragAdorner.RenderTransform = new TranslateTransform(_dragStartPosition.X - _elementDragOffset.X, position.Y - _elementDragOffset.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerMoved(object? sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
DisposeDragAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,6 +14,7 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Sidebar
|
namespace Artemis.UI.Screens.Sidebar
|
||||||
@ -37,13 +38,13 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
_vmFactory = vmFactory;
|
_vmFactory = vmFactory;
|
||||||
|
|
||||||
ProfileCategory = profileCategory;
|
ProfileCategory = profileCategory;
|
||||||
SourceCache<ProfileConfiguration, Guid> profileConfigurations = new(t => t.ProfileId);
|
SourceList<ProfileConfiguration> profileConfigurations = new();
|
||||||
|
|
||||||
// Only show items when not collapsed
|
// Only show items when not collapsed
|
||||||
IObservable<Func<ProfileConfiguration, bool>> profileConfigurationsFilter = this.WhenAnyValue(vm => vm.IsCollapsed).Select(b => new Func<object, bool>(_ => !b));
|
IObservable<Func<ProfileConfiguration, bool>> profileConfigurationsFilter = this.WhenAnyValue(vm => vm.IsCollapsed).Select(b => new Func<object, bool>(_ => !b));
|
||||||
profileConfigurations.Connect()
|
profileConfigurations.Connect()
|
||||||
.SortBy(c => c.Order)
|
|
||||||
.Filter(profileConfigurationsFilter)
|
.Filter(profileConfigurationsFilter)
|
||||||
|
.Sort(SortExpressionComparer<ProfileConfiguration>.Ascending(c => c.Order))
|
||||||
.Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c))
|
.Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c))
|
||||||
.Bind(out ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> profileConfigurationViewModels)
|
.Bind(out ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> profileConfigurationViewModels)
|
||||||
.Subscribe();
|
.Subscribe();
|
||||||
@ -58,7 +59,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
{
|
{
|
||||||
// Update the list of profiles whenever the category fires events
|
// Update the list of profiles whenever the category fires events
|
||||||
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x)
|
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x)
|
||||||
.Subscribe(e => profileConfigurations.AddOrUpdate(e.EventArgs.ProfileConfiguration))
|
.Subscribe(e => profileConfigurations.Add(e.EventArgs.ProfileConfiguration))
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationRemoved += x, x => profileCategory.ProfileConfigurationRemoved -= x)
|
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationRemoved += x, x => profileCategory.ProfileConfigurationRemoved -= x)
|
||||||
.Subscribe(e => profileConfigurations.Remove(e.EventArgs.ProfileConfiguration))
|
.Subscribe(e => profileConfigurations.Remove(e.EventArgs.ProfileConfiguration))
|
||||||
@ -77,7 +78,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
profileConfigurations.Edit(updater =>
|
profileConfigurations.Edit(updater =>
|
||||||
{
|
{
|
||||||
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
updater.AddOrUpdate(profileConfiguration);
|
updater.Add(profileConfiguration);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,5 +136,16 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
ProfileCategory.IsSuspended = !ProfileCategory.IsSuspended;
|
ProfileCategory.IsSuspended = !ProfileCategory.IsSuspended;
|
||||||
_profileService.SaveProfileCategory(ProfileCategory);
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddProfileConfiguration(ProfileConfiguration profileConfiguration, int? index)
|
||||||
|
{
|
||||||
|
ProfileCategory oldCategory = profileConfiguration.Category;
|
||||||
|
ProfileCategory.AddProfileConfiguration(profileConfiguration, index);
|
||||||
|
|
||||||
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
|
// If the profile moved to a new category, also save the old category
|
||||||
|
if (oldCategory != ProfileCategory)
|
||||||
|
_profileService.SaveProfileCategory(oldCategory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,6 +7,9 @@
|
|||||||
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
||||||
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarView">
|
x:Class="Artemis.UI.Screens.Sidebar.SidebarView">
|
||||||
|
<UserControl.Styles>
|
||||||
|
<StyleInclude Source="avares://Avalonia.Xaml.Interactions/Draggable/Styles.axaml" />
|
||||||
|
</UserControl.Styles>
|
||||||
<Grid RowDefinitions="60,Auto,Auto,*,Auto,Auto">
|
<Grid RowDefinitions="60,Auto,Auto,*,Auto,Auto">
|
||||||
<Grid Grid.Row="0" IsHitTestVisible="False" ColumnDefinitions="Auto,*">
|
<Grid Grid.Row="0" IsHitTestVisible="False" ColumnDefinitions="Auto,*">
|
||||||
<Image Grid.Column="0">
|
<Image Grid.Column="0">
|
||||||
@ -33,7 +36,7 @@
|
|||||||
<!-- Categories -->
|
<!-- Categories -->
|
||||||
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ItemsControl Margin="10 2" Items="{Binding SidebarCategories}" />
|
<ItemsControl Margin="10 2" Items="{Binding SidebarCategories}" Classes="profile-categories" />
|
||||||
<Button Content="Add new category"
|
<Button Content="Add new category"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user