mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profile editor - Added focusing indicator
This commit is contained in:
parent
1f311d2295
commit
9602934342
@ -7,7 +7,7 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView"
|
||||||
x:DataType="profileTree:FolderTreeItemViewModel">
|
x:DataType="profileTree:FolderTreeItemViewModel">
|
||||||
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
|
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
||||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
@ -35,8 +35,10 @@
|
|||||||
x:Name="Input"
|
x:Name="Input"
|
||||||
KeyUp="InputElement_OnKeyUp"
|
KeyUp="InputElement_OnKeyUp"
|
||||||
LostFocus="InputElement_OnLostFocus" />
|
LostFocus="InputElement_OnLostFocus" />
|
||||||
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{Binding Folder.Name}" VerticalAlignment="Center" />
|
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{CompiledBinding Folder.Name}" VerticalAlignment="Center" />
|
||||||
<ToggleButton Grid.Column="3"
|
|
||||||
|
<avalonia:MaterialIcon Grid.Column="3" Kind="Eye" IsVisible="{CompiledBinding IsFocused}" ToolTip.Tip="This element is visible because of the current focus mode" Margin="0 0 5 0"/>
|
||||||
|
<ToggleButton Grid.Column="4"
|
||||||
Classes="icon-button icon-button-small"
|
Classes="icon-button icon-button-small"
|
||||||
ToolTip.Tip="Toggle suspended state"
|
ToolTip.Tip="Toggle suspended state"
|
||||||
IsChecked="{CompiledBinding Folder.Suspended}"
|
IsChecked="{CompiledBinding Folder.Suspended}"
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@ -13,16 +15,19 @@ public class FolderTreeItemView : ReactiveUserControl<FolderTreeItemViewModel>
|
|||||||
public FolderTreeItemView()
|
public FolderTreeItemView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
ViewModel?.Rename.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
this.Get<TextBox>("Input").Focus();
|
||||||
|
this.Get<TextBox>("Input").SelectAll();
|
||||||
|
}).DisposeWith(d);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
this.WhenActivated(_ => ViewModel?.Rename.Subscribe(_ =>
|
|
||||||
{
|
|
||||||
this.Get<TextBox>("Input").Focus();
|
|
||||||
this.Get<TextBox>("Input").SelectAll();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputElement_OnKeyUp(object? sender, KeyEventArgs e)
|
private void InputElement_OnKeyUp(object? sender, KeyEventArgs e)
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.LayerTreeItemView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.LayerTreeItemView"
|
||||||
x:DataType="profileTree:LayerTreeItemViewModel">
|
x:DataType="profileTree:LayerTreeItemViewModel">
|
||||||
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
|
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
||||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
@ -27,7 +27,9 @@
|
|||||||
KeyUp="InputElement_OnKeyUp"
|
KeyUp="InputElement_OnKeyUp"
|
||||||
LostFocus="InputElement_OnLostFocus" />
|
LostFocus="InputElement_OnLostFocus" />
|
||||||
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{CompiledBinding Layer.Name}" VerticalAlignment="Center" />
|
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{CompiledBinding Layer.Name}" VerticalAlignment="Center" />
|
||||||
<ToggleButton Grid.Column="3"
|
|
||||||
|
<avalonia:MaterialIcon Grid.Column="3" Kind="Eye" IsVisible="{CompiledBinding IsFocused}" ToolTip.Tip="This element is visible because of the current focus mode" Margin="0 0 5 0"/>
|
||||||
|
<ToggleButton Grid.Column="4"
|
||||||
Classes="icon-button icon-button-small"
|
Classes="icon-button icon-button-small"
|
||||||
ToolTip.Tip="Toggle suspended state"
|
ToolTip.Tip="Toggle suspended state"
|
||||||
IsChecked="{CompiledBinding Layer.Suspended}"
|
IsChecked="{CompiledBinding Layer.Suspended}"
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@ -13,16 +15,19 @@ public class LayerTreeItemView : ReactiveUserControl<LayerTreeItemViewModel>
|
|||||||
public LayerTreeItemView()
|
public LayerTreeItemView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
ViewModel?.Rename.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
this.Get<TextBox>("Input").Focus();
|
||||||
|
this.Get<TextBox>("Input").SelectAll();
|
||||||
|
}).DisposeWith(d);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
this.WhenActivated(_ => ViewModel?.Rename.Subscribe(_ =>
|
|
||||||
{
|
|
||||||
this.Get<TextBox>("Input").Focus();
|
|
||||||
this.Get<TextBox>("Input").SelectAll();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputElement_OnKeyUp(object? sender, KeyEventArgs e)
|
private void InputElement_OnKeyUp(object? sender, KeyEventArgs e)
|
||||||
|
|||||||
@ -152,14 +152,18 @@
|
|||||||
</TreeDataTemplate>
|
</TreeDataTemplate>
|
||||||
</TreeView.ItemTemplate>
|
</TreeView.ItemTemplate>
|
||||||
</TreeView>
|
</TreeView>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1" ColumnDefinitions="*,*">
|
||||||
<Grid.ColumnDefinitions>
|
<StackPanel Grid.Column="0"
|
||||||
<ColumnDefinition />
|
Orientation="Horizontal"
|
||||||
<ColumnDefinition />
|
VerticalAlignment="Center"
|
||||||
</Grid.ColumnDefinitions>
|
Spacing="5"
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Spacing="5" ToolTip.Tip="Focus Mode - Use to disable parts of the profile you're not working on (F to change)">
|
Background="Transparent"
|
||||||
<avalonia:MaterialIcon Kind="ImageFilterCenterFocusStrong" />
|
ToolTip.Tip="Focus Mode - Use to disable parts of the profile you're not working on (F to change)">
|
||||||
<TextBlock Text="{CompiledBinding FocusMode.Value}" />
|
<avalonia:MaterialIcon Kind="EyeOff" IsVisible="{CompiledBinding FocusNone}" />
|
||||||
|
<avalonia:MaterialIcon Kind="Eye" IsVisible="{CompiledBinding !FocusNone}" />
|
||||||
|
<TextBlock Text="Focus disabled" IsVisible="{CompiledBinding FocusNone}" />
|
||||||
|
<TextBlock Text="Focus on folder" IsVisible="{CompiledBinding FocusFolder}" />
|
||||||
|
<TextBlock Text="Focus on selection" IsVisible="{CompiledBinding FocusSelection}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
|
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
|
||||||
<Button Classes="icon-button" ToolTip.Tip="Add new folder to root" Command="{CompiledBinding AddFolder}">
|
<Button Classes="icon-button" ToolTip.Tip="Add new folder to root" Command="{CompiledBinding AddFolder}">
|
||||||
@ -170,7 +174,5 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using System.Reactive.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
@ -17,8 +18,11 @@ public class ProfileTreeViewModel : TreeItemViewModel
|
|||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private TreeItemViewModel? _selectedChild;
|
private TreeItemViewModel? _selectedChild;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _focusNone;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _focusFolder;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _focusSelection;
|
||||||
|
|
||||||
public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, ISettingsService settingsService)
|
public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
|
||||||
: base(null, null, windowService, profileEditorService, profileEditorVmFactory)
|
: base(null, null, windowService, profileEditorService, profileEditorVmFactory)
|
||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
@ -38,6 +42,10 @@ public class ProfileTreeViewModel : TreeItemViewModel
|
|||||||
}).DisposeWith(d);
|
}).DisposeWith(d);
|
||||||
|
|
||||||
profileEditorService.ProfileElement.Subscribe(SelectCurrentProfileElement).DisposeWith(d);
|
profileEditorService.ProfileElement.Subscribe(SelectCurrentProfileElement).DisposeWith(d);
|
||||||
|
|
||||||
|
_focusNone = profileEditorService.FocusMode.Select(f => f == ProfileEditorFocusMode.None).ToProperty(this, vm => vm.FocusNone).DisposeWith(d);
|
||||||
|
_focusFolder = profileEditorService.FocusMode.Select(f => f == ProfileEditorFocusMode.Folder).ToProperty(this, vm => vm.FocusFolder).DisposeWith(d);
|
||||||
|
_focusSelection = profileEditorService.FocusMode.Select(f => f == ProfileEditorFocusMode.Selection).ToProperty(this, vm => vm.FocusSelection).DisposeWith(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.WhenAnyValue(vm => vm.SelectedChild).Subscribe(model =>
|
this.WhenAnyValue(vm => vm.SelectedChild).Subscribe(model =>
|
||||||
@ -45,11 +53,12 @@ public class ProfileTreeViewModel : TreeItemViewModel
|
|||||||
if (model?.ProfileElement is RenderProfileElement renderProfileElement)
|
if (model?.ProfileElement is RenderProfileElement renderProfileElement)
|
||||||
profileEditorService.ChangeCurrentProfileElement(renderProfileElement);
|
profileEditorService.ChangeCurrentProfileElement(renderProfileElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
FocusMode = settingsService.GetSetting("ProfileEditor.FocusMode", ProfileEditorFocusMode.Folder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginSetting<ProfileEditorFocusMode> FocusMode { get; }
|
public bool FocusNone => _focusNone?.Value ?? false;
|
||||||
|
public bool FocusFolder => _focusFolder?.Value ?? false;
|
||||||
|
public bool FocusSelection => _focusSelection?.Value ?? false;
|
||||||
|
|
||||||
public TreeItemViewModel? SelectedChild
|
public TreeItemViewModel? SelectedChild
|
||||||
{
|
{
|
||||||
get => _selectedChild;
|
get => _selectedChild;
|
||||||
|
|||||||
@ -32,6 +32,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
private string? _renameValue;
|
private string? _renameValue;
|
||||||
private bool _renaming;
|
private bool _renaming;
|
||||||
private TimeSpan _time;
|
private TimeSpan _time;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _isFocused;
|
||||||
|
|
||||||
protected TreeItemViewModel(TreeItemViewModel? parent,
|
protected TreeItemViewModel(TreeItemViewModel? parent,
|
||||||
ProfileElement? profileElement,
|
ProfileElement? profileElement,
|
||||||
@ -57,6 +58,11 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
|
_isFocused = ProfileEditorService.FocusMode
|
||||||
|
.CombineLatest(ProfileEditorService.ProfileElement)
|
||||||
|
.Select(tuple => GetIsFocused(tuple.First, tuple.Second))
|
||||||
|
.ToProperty(this, vm => vm.IsFocused);
|
||||||
|
|
||||||
ProfileEditorService.Time.Subscribe(t => _time = t).DisposeWith(d);
|
ProfileEditorService.Time.Subscribe(t => _time = t).DisposeWith(d);
|
||||||
ProfileEditorService.ProfileElement.Subscribe(element => _currentProfileElement = element).DisposeWith(d);
|
ProfileEditorService.ProfileElement.Subscribe(element => _currentProfileElement = element).DisposeWith(d);
|
||||||
SubscribeToProfileElement(d);
|
SubscribeToProfileElement(d);
|
||||||
@ -66,6 +72,8 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
this.WhenAnyValue(vm => vm.IsFlyoutOpen).Subscribe(UpdateCanPaste);
|
this.WhenAnyValue(vm => vm.IsFlyoutOpen).Subscribe(UpdateCanPaste);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsFocused => _isFocused?.Value ?? false;
|
||||||
|
|
||||||
public ProfileElement? ProfileElement
|
public ProfileElement? ProfileElement
|
||||||
{
|
{
|
||||||
get => _profileElement;
|
get => _profileElement;
|
||||||
@ -256,7 +264,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
if (ProfileElement != null)
|
if (ProfileElement != null)
|
||||||
ProfileEditorService.CreateAndAddLayer(ProfileElement);
|
ProfileEditorService.CreateAndAddLayer(ProfileElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteOpenAdaptionHints()
|
private async Task ExecuteOpenAdaptionHints()
|
||||||
{
|
{
|
||||||
if (ProfileElement is not Layer layer)
|
if (ProfileElement is not Layer layer)
|
||||||
@ -277,4 +285,19 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
string[] formats = await Application.Current.Clipboard.GetFormatsAsync();
|
string[] formats = await Application.Current.Clipboard.GetFormatsAsync();
|
||||||
CanPaste = formats.Contains(ProfileElementExtensions.ClipboardDataFormat);
|
CanPaste = formats.Contains(ProfileElementExtensions.ClipboardDataFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool GetIsFocused(ProfileEditorFocusMode focusMode, RenderProfileElement? currentProfileElement)
|
||||||
|
{
|
||||||
|
if (focusMode == ProfileEditorFocusMode.None || currentProfileElement == null)
|
||||||
|
return false;
|
||||||
|
if (focusMode == ProfileEditorFocusMode.Selection)
|
||||||
|
return currentProfileElement == ProfileElement;
|
||||||
|
if (focusMode == ProfileEditorFocusMode.Folder && currentProfileElement?.Parent != null)
|
||||||
|
{
|
||||||
|
// Any direct parent or direct siblings cause focus
|
||||||
|
return currentProfileElement.Parent == ProfileElement?.Parent || currentProfileElement.Parent.GetAllRenderElements().Any(e => e == ProfileElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user