1
0
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:
Robert 2022-08-15 22:42:24 +02:00
parent 1f311d2295
commit 9602934342
7 changed files with 78 additions and 30 deletions

View File

@ -7,7 +7,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView"
x:DataType="profileTree:FolderTreeItemViewModel">
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
<Button Grid.Column="0"
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
@ -35,8 +35,10 @@
x:Name="Input"
KeyUp="InputElement_OnKeyUp"
LostFocus="InputElement_OnLostFocus" />
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{Binding Folder.Name}" VerticalAlignment="Center" />
<ToggleButton Grid.Column="3"
<TextBlock Grid.Column="2" IsVisible="{CompiledBinding !Renaming}" Text="{CompiledBinding Folder.Name}" VerticalAlignment="Center" />
<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"
ToolTip.Tip="Toggle suspended state"
IsChecked="{CompiledBinding Folder.Suspended}"

View File

@ -1,7 +1,9 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using ReactiveUI;
@ -13,16 +15,19 @@ public class FolderTreeItemView : ReactiveUserControl<FolderTreeItemViewModel>
public FolderTreeItemView()
{
InitializeComponent();
this.WhenActivated(d =>
{
ViewModel?.Rename.Subscribe(_ =>
{
this.Get<TextBox>("Input").Focus();
this.Get<TextBox>("Input").SelectAll();
}).DisposeWith(d);
});
}
private void InitializeComponent()
{
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)

View File

@ -7,7 +7,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.LayerTreeItemView"
x:DataType="profileTree:LayerTreeItemViewModel">
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
<Button Grid.Column="0"
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
@ -27,7 +27,9 @@
KeyUp="InputElement_OnKeyUp"
LostFocus="InputElement_OnLostFocus" />
<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"
ToolTip.Tip="Toggle suspended state"
IsChecked="{CompiledBinding Layer.Suspended}"

View File

@ -1,7 +1,9 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using ReactiveUI;
@ -13,16 +15,19 @@ public class LayerTreeItemView : ReactiveUserControl<LayerTreeItemViewModel>
public LayerTreeItemView()
{
InitializeComponent();
this.WhenActivated(d =>
{
ViewModel?.Rename.Subscribe(_ =>
{
this.Get<TextBox>("Input").Focus();
this.Get<TextBox>("Input").SelectAll();
}).DisposeWith(d);
});
}
private void InitializeComponent()
{
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)

View File

@ -152,14 +152,18 @@
</TreeDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<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)">
<avalonia:MaterialIcon Kind="ImageFilterCenterFocusStrong" />
<TextBlock Text="{CompiledBinding FocusMode.Value}" />
<Grid Grid.Row="1" ColumnDefinitions="*,*">
<StackPanel Grid.Column="0"
Orientation="Horizontal"
VerticalAlignment="Center"
Spacing="5"
Background="Transparent"
ToolTip.Tip="Focus Mode - Use to disable parts of the profile you're not working on (F to change)">
<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 Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
<Button Classes="icon-button" ToolTip.Tip="Add new folder to root" Command="{CompiledBinding AddFolder}">
@ -170,7 +174,5 @@
</Button>
</StackPanel>
</Grid>
</Grid>
</UserControl>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
@ -17,8 +18,11 @@ public class ProfileTreeViewModel : TreeItemViewModel
{
private readonly IProfileEditorService _profileEditorService;
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)
{
_profileEditorService = profileEditorService;
@ -38,6 +42,10 @@ public class ProfileTreeViewModel : TreeItemViewModel
}).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 =>
@ -45,11 +53,12 @@ public class ProfileTreeViewModel : TreeItemViewModel
if (model?.ProfileElement is RenderProfileElement 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
{
get => _selectedChild;

View File

@ -32,6 +32,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
private string? _renameValue;
private bool _renaming;
private TimeSpan _time;
private ObservableAsPropertyHelper<bool>? _isFocused;
protected TreeItemViewModel(TreeItemViewModel? parent,
ProfileElement? profileElement,
@ -57,6 +58,11 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
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.ProfileElement.Subscribe(element => _currentProfileElement = element).DisposeWith(d);
SubscribeToProfileElement(d);
@ -66,6 +72,8 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
this.WhenAnyValue(vm => vm.IsFlyoutOpen).Subscribe(UpdateCanPaste);
}
public bool IsFocused => _isFocused?.Value ?? false;
public ProfileElement? ProfileElement
{
get => _profileElement;
@ -256,7 +264,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
if (ProfileElement != null)
ProfileEditorService.CreateAndAddLayer(ProfileElement);
}
private async Task ExecuteOpenAdaptionHints()
{
if (ProfileElement is not Layer layer)
@ -277,4 +285,19 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
string[] formats = await Application.Current.Clipboard.GetFormatsAsync();
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;
}
}