mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profile tree - Fixed dragging while renaming
Profile tree - Fixed dragging folders onto themselves Profile tree - Suspend keybinds while renaming Brushes - Added brush presets UI Numberbox - Removed double validation error
This commit is contained in:
parent
a23af68a12
commit
29ef160975
@ -342,7 +342,7 @@ namespace Artemis.Core
|
|||||||
int current = 2;
|
int current = 2;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (Children.All(c => c is Layer && c.Name != $"{baseName} ({current})"))
|
if (Children.Where(c => c is Layer).All(c => c.Name != $"{baseName} ({current})"))
|
||||||
return $"{baseName} ({current})";
|
return $"{baseName} ({current})";
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
@ -361,7 +361,7 @@ namespace Artemis.Core
|
|||||||
int current = 2;
|
int current = 2;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (Children.All(c => c is Folder && c.Name != $"{baseName} ({current})"))
|
if (Children.Where(c => c is Folder).All(c => c.Name != $"{baseName} ({current})"))
|
||||||
return $"{baseName} ({current})";
|
return $"{baseName} ({current})";
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,11 @@ public interface IProfileEditorService : IArtemisSharedUIService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IObservable<bool> SuspendedEditing { get; }
|
IObservable<bool> SuspendedEditing { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an observable of the suspended keybindings state.
|
||||||
|
/// </summary>
|
||||||
|
IObservable<bool> SuspendedKeybindings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an observable read only collection of all available editor tools.
|
/// Gets an observable read only collection of all available editor tools.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -97,6 +102,12 @@ public interface IProfileEditorService : IArtemisSharedUIService
|
|||||||
/// <param name="suspend">The new suspended state.</param>
|
/// <param name="suspend">The new suspended state.</param>
|
||||||
void ChangeSuspendedEditing(bool suspend);
|
void ChangeSuspendedEditing(bool suspend);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the current suspended keybindings state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="suspend">The new suspended state.</param>
|
||||||
|
void ChangeSuspendedKeybindings(bool suspend);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects the provided keyframe.
|
/// Selects the provided keyframe.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -30,6 +30,7 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
private readonly BehaviorSubject<RenderProfileElement?> _profileElementSubject = new(null);
|
private readonly BehaviorSubject<RenderProfileElement?> _profileElementSubject = new(null);
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
private readonly BehaviorSubject<bool> _suspendedEditingSubject = new(false);
|
private readonly BehaviorSubject<bool> _suspendedEditingSubject = new(false);
|
||||||
|
private readonly BehaviorSubject<bool> _suspendedKeybindingsSubject = new(false);
|
||||||
private readonly BehaviorSubject<TimeSpan> _timeSubject = new(TimeSpan.Zero);
|
private readonly BehaviorSubject<TimeSpan> _timeSubject = new(TimeSpan.Zero);
|
||||||
private readonly SourceList<IToolViewModel> _tools;
|
private readonly SourceList<IToolViewModel> _tools;
|
||||||
private readonly SourceList<ILayerPropertyKeyframe> _selectedKeyframes;
|
private readonly SourceList<ILayerPropertyKeyframe> _selectedKeyframes;
|
||||||
@ -64,6 +65,7 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
Time = _timeSubject.AsObservable();
|
Time = _timeSubject.AsObservable();
|
||||||
Playing = _playingSubject.AsObservable();
|
Playing = _playingSubject.AsObservable();
|
||||||
SuspendedEditing = _suspendedEditingSubject.AsObservable();
|
SuspendedEditing = _suspendedEditingSubject.AsObservable();
|
||||||
|
SuspendedKeybindings = _suspendedKeybindingsSubject.AsObservable();
|
||||||
PixelsPerSecond = _pixelsPerSecondSubject.AsObservable();
|
PixelsPerSecond = _pixelsPerSecondSubject.AsObservable();
|
||||||
Tools = tools;
|
Tools = tools;
|
||||||
SelectedKeyframes = selectedKeyframes;
|
SelectedKeyframes = selectedKeyframes;
|
||||||
@ -90,6 +92,7 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
public IObservable<ILayerProperty?> LayerProperty { get; }
|
public IObservable<ILayerProperty?> LayerProperty { get; }
|
||||||
public IObservable<ProfileEditorHistory?> History { get; }
|
public IObservable<ProfileEditorHistory?> History { get; }
|
||||||
public IObservable<bool> SuspendedEditing { get; }
|
public IObservable<bool> SuspendedEditing { get; }
|
||||||
|
public IObservable<bool> SuspendedKeybindings { get; }
|
||||||
public IObservable<TimeSpan> Time { get; }
|
public IObservable<TimeSpan> Time { get; }
|
||||||
public IObservable<bool> Playing { get; }
|
public IObservable<bool> Playing { get; }
|
||||||
public IObservable<int> PixelsPerSecond { get; }
|
public IObservable<int> PixelsPerSecond { get; }
|
||||||
@ -138,6 +141,7 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
|
|
||||||
_profileConfigurationSubject.OnNext(profileConfiguration);
|
_profileConfigurationSubject.OnNext(profileConfiguration);
|
||||||
ChangeTime(TimeSpan.Zero);
|
ChangeTime(TimeSpan.Zero);
|
||||||
|
ChangeSuspendedKeybindings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeCurrentProfileElement(RenderProfileElement? renderProfileElement)
|
public void ChangeCurrentProfileElement(RenderProfileElement? renderProfileElement)
|
||||||
@ -178,6 +182,14 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ChangeSuspendedKeybindings(bool suspend)
|
||||||
|
{
|
||||||
|
if (_suspendedKeybindingsSubject.Value == suspend)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_suspendedKeybindingsSubject.OnNext(suspend);
|
||||||
|
}
|
||||||
|
|
||||||
public void SelectKeyframe(ILayerPropertyKeyframe? keyframe, bool expand, bool toggle)
|
public void SelectKeyframe(ILayerPropertyKeyframe? keyframe, bool expand, bool toggle)
|
||||||
{
|
{
|
||||||
if (keyframe == null)
|
if (keyframe == null)
|
||||||
|
|||||||
@ -24,83 +24,6 @@
|
|||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
|
|
||||||
<!-- Add Styles Here -->
|
<!-- Add Styles Here -->
|
||||||
<Style Selector="TextBox.NumberBoxTextBoxStyle">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<ControlTemplate>
|
|
||||||
<DataValidationErrors>
|
|
||||||
<Panel>
|
|
||||||
<Border Name="PART_BorderElement"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
MinWidth="{TemplateBinding MinWidth}"
|
|
||||||
MinHeight="{TemplateBinding MinHeight}"
|
|
||||||
RenderTransform="scaleY(-1)"
|
|
||||||
CornerRadius="{TemplateBinding CornerRadius}" />
|
|
||||||
|
|
||||||
<Border Margin="{TemplateBinding BorderThickness}">
|
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto" >
|
|
||||||
<TextBlock Name="PART_Prefix"
|
|
||||||
Text="{TemplateBinding attachedProperties:TextBoxAssist.PrefixText}"
|
|
||||||
Padding="{TemplateBinding Padding}"
|
|
||||||
IsHitTestVisible="False"/>
|
|
||||||
<DockPanel x:Name="PART_InnerDockPanel"
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.ColumnSpan="1"
|
|
||||||
Margin="{TemplateBinding Padding}">
|
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
|
|
||||||
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
|
|
||||||
<Panel>
|
|
||||||
<TextBlock Name="PART_Watermark"
|
|
||||||
Text="{TemplateBinding Watermark}"
|
|
||||||
TextAlignment="{TemplateBinding TextAlignment}"
|
|
||||||
TextWrapping="{TemplateBinding TextWrapping}"
|
|
||||||
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
|
||||||
IsHitTestVisible="False"/>
|
|
||||||
<TextPresenter Name="PART_TextPresenter"
|
|
||||||
Text="{TemplateBinding Text, Mode=TwoWay}"
|
|
||||||
CaretIndex="{TemplateBinding CaretIndex}"
|
|
||||||
SelectionStart="{TemplateBinding SelectionStart}"
|
|
||||||
SelectionEnd="{TemplateBinding SelectionEnd}"
|
|
||||||
TextAlignment="{TemplateBinding TextAlignment}"
|
|
||||||
TextWrapping="{TemplateBinding TextWrapping}"
|
|
||||||
PasswordChar="{TemplateBinding PasswordChar}"
|
|
||||||
RevealPassword="{TemplateBinding RevealPassword}"
|
|
||||||
SelectionBrush="{TemplateBinding SelectionBrush}"
|
|
||||||
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
|
|
||||||
CaretBrush="{TemplateBinding CaretBrush}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
|
||||||
</Panel>
|
|
||||||
</ScrollViewer>
|
|
||||||
</DockPanel>
|
|
||||||
<StackPanel Orientation="Horizontal" Grid.Column="2" Grid.ColumnSpan="1">
|
|
||||||
<TextBlock Name="PART_Suffix"
|
|
||||||
Text="{TemplateBinding attachedProperties:TextBoxAssist.SuffixText}"
|
|
||||||
Padding="{TemplateBinding Padding}"
|
|
||||||
IsHitTestVisible="False"/>
|
|
||||||
<ContentPresenter Content="{TemplateBinding InnerRightContent}"
|
|
||||||
Name="InnerRightContent"/>
|
|
||||||
<Viewbox Margin="{DynamicResource NumberBoxPopupIndicatorMargin}"
|
|
||||||
VerticalAlignment="Center" HorizontalAlignment="Center"
|
|
||||||
Width="18" Height="18"
|
|
||||||
Name="PopupIndicator">
|
|
||||||
<controls:FontIcon Glyph=""
|
|
||||||
FontFamily="{DynamicResource SymbolThemeFontFamily}"
|
|
||||||
FontSize="24"
|
|
||||||
Foreground="{DynamicResource NumberBoxPopupIndicatorForeground}" />
|
|
||||||
</Viewbox>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</Panel>
|
|
||||||
</DataValidationErrors>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Prefix">
|
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Prefix">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
||||||
<Setter Property="Margin" Value="-4 0 -12 0"></Setter>
|
<Setter Property="Margin" Value="-4 0 -12 0"></Setter>
|
||||||
@ -122,8 +45,4 @@
|
|||||||
<Setter Property="attachedProperties:TextBoxAssist.PrefixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.PrefixText}"></Setter>
|
<Setter Property="attachedProperties:TextBoxAssist.PrefixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.PrefixText}"></Setter>
|
||||||
<Setter Property="attachedProperties:TextBoxAssist.SuffixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.SuffixText}"></Setter>
|
<Setter Property="attachedProperties:TextBoxAssist.SuffixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.SuffixText}"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle">
|
|
||||||
<Setter Property="DataValidationErrors.Errors" Value="{TemplateBinding DataValidationErrors.Errors}" />
|
|
||||||
</Style>
|
|
||||||
</Styles>
|
</Styles>
|
||||||
@ -105,7 +105,7 @@ public class SimpleContextDragBehavior : Behavior<Control>
|
|||||||
private void AssociatedObject_PointerPressed(object? sender, PointerPressedEventArgs e)
|
private void AssociatedObject_PointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
PointerPointProperties properties = e.GetCurrentPoint(AssociatedObject).Properties;
|
PointerPointProperties properties = e.GetCurrentPoint(AssociatedObject).Properties;
|
||||||
if (!properties.IsLeftButtonPressed)
|
if (!properties.IsLeftButtonPressed || FocusManager.Instance?.Current is TextBox)
|
||||||
return;
|
return;
|
||||||
if (e.Source is not IControl control || AssociatedObject?.DataContext != control.DataContext)
|
if (e.Source is not IControl control || AssociatedObject?.DataContext != control.DataContext)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using Artemis.Core.LayerBrushes;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||||
using Artemis.UI.Shared.Services.PropertyInput;
|
using Artemis.UI.Shared.Services.PropertyInput;
|
||||||
@ -63,7 +64,14 @@ public class BrushPropertyInputViewModel : PropertyInputViewModel<LayerBrushRefe
|
|||||||
|
|
||||||
_profileEditorService.ExecuteCommand(new ChangeLayerBrush(layer, SelectedDescriptor));
|
_profileEditorService.ExecuteCommand(new ChangeLayerBrush(layer, SelectedDescriptor));
|
||||||
if (layer.LayerBrush?.Presets != null && layer.LayerBrush.Presets.Any())
|
if (layer.LayerBrush?.Presets != null && layer.LayerBrush.Presets.Any())
|
||||||
Dispatcher.UIThread.InvokeAsync(() => _windowService.CreateContentDialog().WithViewModel(out LayerBrushPresetViewModel _, ("layerBrush", layer.LayerBrush)).ShowAsync());
|
{
|
||||||
|
Dispatcher.UIThread.InvokeAsync(() => _windowService.CreateContentDialog()
|
||||||
|
.WithTitle("Select preset")
|
||||||
|
.WithViewModel(out LayerBrushPresetViewModel _, ("layerBrush", layer.LayerBrush))
|
||||||
|
.WithDefaultButton(ContentDialogButton.Close)
|
||||||
|
.WithCloseButtonText("Use defaults")
|
||||||
|
.ShowAsync());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Overrides of PropertyInputViewModel<LayerBrushReference>
|
#region Overrides of PropertyInputViewModel<LayerBrushReference>
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
x:DataType="device:DevicePropertiesViewModel"
|
x:DataType="device:DevicePropertiesViewModel"
|
||||||
Icon="/Assets/Images/Logo/application.ico"
|
Icon="/Assets/Images/Logo/application.ico"
|
||||||
Title="Artemis | Device Properties"
|
Title="Artemis | Device Properties"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
Width="1250"
|
Width="1250"
|
||||||
Height="900">
|
Height="900">
|
||||||
<controls1:CoreWindow.KeyBindings>
|
<controls1:CoreWindow.KeyBindings>
|
||||||
|
|||||||
@ -6,6 +6,8 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
@ -23,6 +25,8 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
private bool _repeating;
|
private bool _repeating;
|
||||||
private bool _repeatSegment;
|
private bool _repeatSegment;
|
||||||
private bool _repeatTimeline;
|
private bool _repeatTimeline;
|
||||||
|
private ReactiveCommand<Unit, Unit>? _togglePlay;
|
||||||
|
private ReactiveCommand<Unit, Unit>? _playFromStart;
|
||||||
|
|
||||||
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
@ -36,15 +40,15 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
_currentTime = _profileEditorService.Time.ToProperty(this, vm => vm.CurrentTime).DisposeWith(d);
|
_currentTime = _profileEditorService.Time.ToProperty(this, vm => vm.CurrentTime).DisposeWith(d);
|
||||||
_formattedCurrentTime = _profileEditorService.Time.Select(t => $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}").ToProperty(this, vm => vm.FormattedCurrentTime).DisposeWith(d);
|
_formattedCurrentTime = _profileEditorService.Time.Select(t => $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}").ToProperty(this, vm => vm.FormattedCurrentTime).DisposeWith(d);
|
||||||
_playing = _profileEditorService.Playing.ToProperty(this, vm => vm.Playing).DisposeWith(d);
|
_playing = _profileEditorService.Playing.ToProperty(this, vm => vm.Playing).DisposeWith(d);
|
||||||
|
|
||||||
_lastUpdate = DateTime.MinValue;
|
_lastUpdate = DateTime.MinValue;
|
||||||
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(60.0 / 1000), DispatcherPriority.Render, Update);
|
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(60.0 / 1000), DispatcherPriority.Render, Update);
|
||||||
updateTimer.Start();
|
updateTimer.Start();
|
||||||
Disposable.Create(() => updateTimer.Stop()).DisposeWith(d);
|
Disposable.Create(() => updateTimer.Stop()).DisposeWith(d);
|
||||||
|
|
||||||
|
PlayFromStart = ReactiveCommand.Create(ExecutePlayFromStart, _profileEditorService.SuspendedKeybindings.Select(s => !s)).DisposeWith(d);
|
||||||
|
TogglePlay = ReactiveCommand.Create(ExecuteTogglePlay, _profileEditorService.SuspendedKeybindings.Select(s => !s)).DisposeWith(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
PlayFromStart = ReactiveCommand.Create(ExecutePlayFromStart);
|
|
||||||
TogglePlay = ReactiveCommand.Create(ExecuteTogglePlay);
|
|
||||||
GoToStart = ReactiveCommand.Create(ExecuteGoToStart);
|
GoToStart = ReactiveCommand.Create(ExecuteGoToStart);
|
||||||
GoToEnd = ReactiveCommand.Create(ExecuteGoToEnd);
|
GoToEnd = ReactiveCommand.Create(ExecuteGoToEnd);
|
||||||
GoToPreviousFrame = ReactiveCommand.Create(ExecuteGoToPreviousFrame);
|
GoToPreviousFrame = ReactiveCommand.Create(ExecuteGoToPreviousFrame);
|
||||||
@ -74,8 +78,18 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
set => RaiseAndSetIfChanged(ref _repeatSegment, value);
|
set => RaiseAndSetIfChanged(ref _repeatSegment, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit,Unit> PlayFromStart { get; }
|
public ReactiveCommand<Unit, Unit>? PlayFromStart
|
||||||
public ReactiveCommand<Unit,Unit> TogglePlay { get; }
|
{
|
||||||
|
get => _playFromStart;
|
||||||
|
set => RaiseAndSetIfChanged(ref _playFromStart, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit>? TogglePlay
|
||||||
|
{
|
||||||
|
get => _togglePlay;
|
||||||
|
set => RaiseAndSetIfChanged(ref _togglePlay, value);
|
||||||
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit,Unit> GoToStart { get; }
|
public ReactiveCommand<Unit,Unit> GoToStart { get; }
|
||||||
public ReactiveCommand<Unit,Unit> GoToEnd { get; }
|
public ReactiveCommand<Unit,Unit> GoToEnd { get; }
|
||||||
public ReactiveCommand<Unit,Unit> GoToPreviousFrame { get; }
|
public ReactiveCommand<Unit,Unit> GoToPreviousFrame { get; }
|
||||||
|
|||||||
@ -49,7 +49,8 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
|
|||||||
IVisual? targetVisual = treeView.GetVisualAt(position).FindAncestorOfType<TreeViewItem>();
|
IVisual? targetVisual = treeView.GetVisualAt(position).FindAncestorOfType<TreeViewItem>();
|
||||||
if (sourceContext is not T sourceNode || targetContext is not ProfileTreeViewModel vm || targetVisual is not IControl {DataContext: T targetNode})
|
if (sourceContext is not T sourceNode || targetContext is not ProfileTreeViewModel vm || targetVisual is not IControl {DataContext: T targetNode})
|
||||||
return false;
|
return false;
|
||||||
|
if (bExecute && targetNode == sourceNode)
|
||||||
|
return false;
|
||||||
TreeItemViewModel? sourceParent = sourceNode.Parent;
|
TreeItemViewModel? sourceParent = sourceNode.Parent;
|
||||||
TreeItemViewModel? targetParent = targetNode.Parent;
|
TreeItemViewModel? targetParent = targetNode.Parent;
|
||||||
ObservableCollection<TreeItemViewModel> sourceNodes = sourceParent is { } ? sourceParent.Children : vm.Children;
|
ObservableCollection<TreeItemViewModel> sourceNodes = sourceParent is { } ? sourceParent.Children : vm.Children;
|
||||||
|
|||||||
@ -140,11 +140,13 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
ProfileEditorService.ExecuteCommand(new RenameProfileElement(ProfileElement, RenameValue));
|
ProfileEditorService.ExecuteCommand(new RenameProfileElement(ProfileElement, RenameValue));
|
||||||
Renaming = false;
|
Renaming = false;
|
||||||
|
ProfileEditorService.ChangeSuspendedKeybindings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelRename()
|
public void CancelRename()
|
||||||
{
|
{
|
||||||
Renaming = false;
|
Renaming = false;
|
||||||
|
ProfileEditorService.ChangeSuspendedKeybindings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertElement(TreeItemViewModel elementViewModel, int targetIndex)
|
public void InsertElement(TreeItemViewModel elementViewModel, int targetIndex)
|
||||||
@ -237,6 +239,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
Renaming = true;
|
Renaming = true;
|
||||||
RenameValue = ProfileElement?.Name;
|
RenameValue = ProfileElement?.Name;
|
||||||
|
ProfileEditorService.ChangeSuspendedKeybindings(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteAddFolder()
|
private void ExecuteAddFolder()
|
||||||
|
|||||||
@ -0,0 +1,64 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs"
|
||||||
|
xmlns:layerBrushes="clr-namespace:Artemis.Core.LayerBrushes;assembly=Artemis.Core"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs.LayerBrushPresetView"
|
||||||
|
x:DataType="dialogs:LayerBrushPresetViewModel"
|
||||||
|
Width="500">
|
||||||
|
<Grid RowDefinitions="Auto,*">
|
||||||
|
<TextBox Name="SearchBox" Text="{CompiledBinding SearchText}" Margin="0 0 0 15" Watermark="Search" />
|
||||||
|
<ListBox Name="EffectDescriptorsList"
|
||||||
|
Grid.Row="1"
|
||||||
|
Items="{CompiledBinding Presets}"
|
||||||
|
IsVisible="{CompiledBinding Presets.Count}"
|
||||||
|
Height="300">
|
||||||
|
|
||||||
|
<ListBox.DataTemplates>
|
||||||
|
<DataTemplate DataType="{x:Type layerBrushes:ILayerBrushPreset}">
|
||||||
|
<Grid RowDefinitions="Auto,*"
|
||||||
|
ColumnDefinitions="Auto,Auto"
|
||||||
|
Background="Transparent"
|
||||||
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
|
Margin="0 4"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<shared:ArtemisIcon Grid.Column="0"
|
||||||
|
Grid.RowSpan="2"
|
||||||
|
Icon="{CompiledBinding Icon}"
|
||||||
|
Width="24"
|
||||||
|
Height="24"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0 0 15 0" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="0"
|
||||||
|
Classes="BodyStrongTextBlockStyle"
|
||||||
|
Text="{CompiledBinding Name}"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Width="450"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Foreground="{DynamicResource TextFillColorSecondary}"
|
||||||
|
Text="{CompiledBinding Description}"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Width="450"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.DataTemplates>
|
||||||
|
</ListBox>
|
||||||
|
<Grid Grid.Row="1" Height="300">
|
||||||
|
<StackPanel VerticalAlignment="Center"
|
||||||
|
Spacing="20"
|
||||||
|
IsVisible="{CompiledBinding !Presets.Count}">
|
||||||
|
<avalonia:MaterialIcon Kind="CloseCircle" Width="32" Height="32" />
|
||||||
|
<TextBlock Classes="h5" TextAlignment="Center">None of the presets match your search</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using Artemis.Core.LayerBrushes;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs;
|
||||||
|
|
||||||
|
public partial class LayerBrushPresetView : ReactiveUserControl<LayerBrushPresetViewModel>
|
||||||
|
{
|
||||||
|
public LayerBrushPresetView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is not IDataContextProvider {DataContext: ILayerBrushPreset preset} || ViewModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ViewModel?.SelectPreset(preset);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,61 @@
|
|||||||
using Artemis.Core.LayerBrushes;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.LayerBrushes;
|
||||||
|
using Artemis.Core.LayerEffects;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
|
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||||
|
using DynamicData;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs;
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.Dialogs;
|
||||||
|
|
||||||
public class LayerBrushPresetViewModel : ContentDialogViewModelBase
|
public class LayerBrushPresetViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
|
private readonly BaseLayerBrush _layerBrush;
|
||||||
|
private string? _searchText;
|
||||||
|
|
||||||
public LayerBrushPresetViewModel(BaseLayerBrush layerBrush)
|
public LayerBrushPresetViewModel(BaseLayerBrush layerBrush)
|
||||||
{
|
{
|
||||||
LayerBrush = layerBrush;
|
_layerBrush = layerBrush;
|
||||||
|
|
||||||
|
SourceList<ILayerBrushPreset> presetsSourceList = new();
|
||||||
|
if (layerBrush.Presets != null)
|
||||||
|
presetsSourceList.AddRange(layerBrush.Presets);
|
||||||
|
IObservable<Func<ILayerBrushPreset, bool>> presetsFilter = this.WhenAnyValue(vm => vm.SearchText).Select(CreatePredicate);
|
||||||
|
|
||||||
|
presetsSourceList.Connect()
|
||||||
|
.Filter(presetsFilter)
|
||||||
|
.Bind(out ReadOnlyObservableCollection<ILayerBrushPreset> presets)
|
||||||
|
.Subscribe();
|
||||||
|
Presets = presets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseLayerBrush LayerBrush { get; }
|
public ReadOnlyObservableCollection<ILayerBrushPreset> Presets { get; }
|
||||||
|
|
||||||
|
public string? SearchText
|
||||||
|
{
|
||||||
|
get => _searchText;
|
||||||
|
set => RaiseAndSetIfChanged(ref _searchText, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectPreset(ILayerBrushPreset preset)
|
||||||
|
{
|
||||||
|
_layerBrush.BaseProperties?.ResetAllLayerProperties();
|
||||||
|
preset.Apply();
|
||||||
|
ContentDialog?.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<ILayerBrushPreset, bool> CreatePredicate(string? search)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(search))
|
||||||
|
return _ => true;
|
||||||
|
|
||||||
|
search = search.Trim();
|
||||||
|
return data => data.Name.Contains(search, StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
data.Description.Contains(search, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -9,7 +9,8 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Windows.BrushConfigurationWindowView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Windows.BrushConfigurationWindowView"
|
||||||
Title="Artemis | Brush configuration"
|
Title="Artemis | Brush configuration"
|
||||||
Width="{Binding Configuration.DialogWidth}"
|
Width="{Binding Configuration.DialogWidth}"
|
||||||
Height="{Binding Configuration.DialogHeight}">
|
Height="{Binding Configuration.DialogHeight}"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
<Panel>
|
<Panel>
|
||||||
<ContentControl Content="{Binding ConfigurationViewModel}" />
|
<ContentControl Content="{Binding ConfigurationViewModel}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|||||||
@ -9,7 +9,8 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Windows.EffectConfigurationWindowView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Windows.EffectConfigurationWindowView"
|
||||||
Title="Artemis | Effect configuration"
|
Title="Artemis | Effect configuration"
|
||||||
Width="{Binding Configuration.DialogWidth}"
|
Width="{Binding Configuration.DialogWidth}"
|
||||||
Height="{Binding Configuration.DialogHeight}">
|
Height="{Binding Configuration.DialogHeight}"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
<Panel>
|
<Panel>
|
||||||
<ContentControl Content="{Binding ConfigurationViewModel}" />
|
<ContentControl Content="{Binding ConfigurationViewModel}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|||||||
@ -1680,10 +1680,7 @@
|
|||||||
"Unosquare.Swan.Lite": {
|
"Unosquare.Swan.Lite": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "3.0.0",
|
"resolved": "3.0.0",
|
||||||
"contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==",
|
"contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw=="
|
||||||
"dependencies": {
|
|
||||||
"System.ValueTuple": "4.5.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"artemis.core": {
|
"artemis.core": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user