mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Sidebar - Refactored category VM to fix all issues with it I could find
Sidebar - Streamlined design Sidebar - Increase width on wide window sizes Profile editor - Implement File and Help menus
This commit is contained in:
parent
35f83e58e5
commit
78479c0fa2
7
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
7
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
@ -18,8 +18,11 @@
|
|||||||
<entry key="Artemis.UI.Windows/App.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
<entry key="Artemis.UI.Windows/App.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||||
<entry key="Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
<entry key="Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||||
<entry key="Artemis.UI/DefaultTypes/PropertyInput/SKSizePropertyInputView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/DefaultTypes/PropertyInput/SKSizePropertyInputView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/MainWindow.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Plugins/PluginFeatureView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Plugins/PluginFeatureView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Plugins/PluginSettingsView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Plugins/PluginSettingsView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
@ -28,9 +31,13 @@
|
|||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/TransformToolView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/TransformToolView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/ProfileEditorView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Root/SplashView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/Root/SplashView.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/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/SidebarCategoryView.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/VisualScripting/NodeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/VisualScripting/NodeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
|||||||
@ -141,6 +141,20 @@ public interface IProfileEditorService : IArtemisSharedUIService
|
|||||||
/// <returns>The rounded time.</returns>
|
/// <returns>The rounded time.</returns>
|
||||||
TimeSpan RoundTime(TimeSpan time);
|
TimeSpan RoundTime(TimeSpan time);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new folder as a sibling or child of the given target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">The target, if this is a layer the new layer will become a sibling, otherwise a child.</param>
|
||||||
|
/// <returns>The resulting folder.</returns>
|
||||||
|
Folder CreateAndAddFolder(ProfileElement target);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new layer with the default brush and all current LEDs as a sibling or child of the given target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">The target, if this is a layer the new layer will become a sibling, otherwise a child.</param>
|
||||||
|
/// <returns>The resulting layer.</returns>
|
||||||
|
Layer CreateAndAddLayer(ProfileElement target);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the provided command and adds it to the history.
|
/// Executes the provided command and adds it to the history.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -18,6 +18,8 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
private readonly BehaviorSubject<ILayerProperty?> _layerPropertySubject = new(null);
|
private readonly BehaviorSubject<ILayerProperty?> _layerPropertySubject = new(null);
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IModuleService _moduleService;
|
private readonly IModuleService _moduleService;
|
||||||
|
private readonly IRgbService _rgbService;
|
||||||
|
private readonly ILayerBrushService _layerBrushService;
|
||||||
private readonly BehaviorSubject<int> _pixelsPerSecondSubject = new(120);
|
private readonly BehaviorSubject<int> _pixelsPerSecondSubject = new(120);
|
||||||
private readonly BehaviorSubject<bool> _playingSubject = new(false);
|
private readonly BehaviorSubject<bool> _playingSubject = new(false);
|
||||||
private readonly BehaviorSubject<ProfileConfiguration?> _profileConfigurationSubject = new(null);
|
private readonly BehaviorSubject<ProfileConfiguration?> _profileConfigurationSubject = new(null);
|
||||||
@ -30,11 +32,18 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private ProfileEditorCommandScope? _profileEditorHistoryScope;
|
private ProfileEditorCommandScope? _profileEditorHistoryScope;
|
||||||
|
|
||||||
public ProfileEditorService(ILogger logger, IProfileService profileService, IModuleService moduleService, IWindowService windowService)
|
public ProfileEditorService(ILogger logger,
|
||||||
|
IProfileService profileService,
|
||||||
|
IModuleService moduleService,
|
||||||
|
IRgbService rgbService,
|
||||||
|
ILayerBrushService layerBrushService,
|
||||||
|
IWindowService windowService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
_moduleService = moduleService;
|
_moduleService = moduleService;
|
||||||
|
_rgbService = rgbService;
|
||||||
|
_layerBrushService = layerBrushService;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
|
|
||||||
ProfileConfiguration = _profileConfigurationSubject.AsObservable();
|
ProfileConfiguration = _profileConfigurationSubject.AsObservable();
|
||||||
@ -293,6 +302,48 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
return TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds));
|
return TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Folder CreateAndAddFolder(ProfileElement target)
|
||||||
|
{
|
||||||
|
if (target is Layer targetLayer)
|
||||||
|
{
|
||||||
|
Folder folder = new(targetLayer.Parent, targetLayer.Parent.GetNewFolderName());
|
||||||
|
ExecuteCommand(new AddProfileElement(folder, targetLayer.Parent, targetLayer.Order));
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Folder folder = new(target, target.GetNewFolderName());
|
||||||
|
ExecuteCommand(new AddProfileElement(folder, target, 0));
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Layer CreateAndAddLayer(ProfileElement target)
|
||||||
|
{
|
||||||
|
if (target is Layer targetLayer)
|
||||||
|
{
|
||||||
|
Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName());
|
||||||
|
_layerBrushService.ApplyDefaultBrush(layer);
|
||||||
|
|
||||||
|
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
|
||||||
|
ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order));
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Layer layer = new(target, target.GetNewLayerName());
|
||||||
|
_layerBrushService.ApplyDefaultBrush(layer);
|
||||||
|
|
||||||
|
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
|
||||||
|
ExecuteCommand(new AddProfileElement(layer, target, 0));
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ChangePixelsPerSecond(int pixelsPerSecond)
|
public void ChangePixelsPerSecond(int pixelsPerSecond)
|
||||||
{
|
{
|
||||||
_pixelsPerSecondSubject.OnNext(pixelsPerSecond);
|
_pixelsPerSecondSubject.OnNext(pixelsPerSecond);
|
||||||
|
|||||||
@ -7,9 +7,15 @@
|
|||||||
x:Class="Artemis.UI.MainWindow"
|
x:Class="Artemis.UI.MainWindow"
|
||||||
Icon="/Assets/Images/Logo/application.ico"
|
Icon="/Assets/Images/Logo/application.ico"
|
||||||
Title="Artemis 2.0">
|
Title="Artemis 2.0">
|
||||||
<Panel>
|
<Panel Name="RootPanel">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ContentControl Content="{Binding SidebarViewModel}" DockPanel.Dock="Left"></ContentControl>
|
<ContentControl Name="SidebarContentControl" Content="{Binding SidebarViewModel}" DockPanel.Dock="Left" Width="240">
|
||||||
|
<ContentControl.Transitions>
|
||||||
|
<Transitions>
|
||||||
|
<DoubleTransition Property="Width" Duration="0:0:0.2" Easing="CubicEaseOut"></DoubleTransition>
|
||||||
|
</Transitions>
|
||||||
|
</ContentControl.Transitions>
|
||||||
|
</ContentControl>
|
||||||
<Border Background="Transparent" Name="TitleBar" DockPanel.Dock="Top">
|
<Border Background="Transparent" Name="TitleBar" DockPanel.Dock="Top">
|
||||||
<ContentControl Content="{Binding TitleBarViewModel}" />
|
<ContentControl Content="{Binding TitleBarViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@ -12,15 +12,28 @@ namespace Artemis.UI
|
|||||||
{
|
{
|
||||||
public class MainWindow : ReactiveCoreWindow<RootViewModel>
|
public class MainWindow : ReactiveCoreWindow<RootViewModel>
|
||||||
{
|
{
|
||||||
|
private readonly Panel _rootPanel;
|
||||||
|
private readonly ContentControl _sidebarContentControl;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
Opened += OnOpened;
|
Opened += OnOpened;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_rootPanel = this.Get<Panel>("RootPanel");
|
||||||
|
_sidebarContentControl = this.Get<ContentControl>("SidebarContentControl");
|
||||||
|
_rootPanel.LayoutUpdated += OnLayoutUpdated;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
this.AttachDevTools();
|
this.AttachDevTools();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Replace with a media query once https://github.com/AvaloniaUI/Avalonia/pull/7938 is implemented
|
||||||
|
private void OnLayoutUpdated(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_sidebarContentControl.Width = _rootPanel.Bounds.Width >= 1800 ? 300 : 240;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnOpened(object? sender, EventArgs e)
|
private void OnOpened(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Opened -= OnOpened;
|
Opened -= OnOpened;
|
||||||
@ -32,12 +45,6 @@ namespace Artemis.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupTitlebar()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.AlwaysOnConditionView">
|
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.AlwaysOnConditionView">
|
||||||
|
|
||||||
<DockPanel VerticalAlignment="Top" Margin="0 5">
|
<DockPanel VerticalAlignment="Top" Margin="0 5">
|
||||||
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0"/>
|
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0" />
|
||||||
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||||
TextWrapping="Wrap">
|
TextWrapping="Wrap">
|
||||||
After playing the start segment, the main segment is endlessly repeated.
|
After playing the start segment, the main segment is endlessly repeated.
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
DataModelPath="{CompiledBinding EventPath}"
|
DataModelPath="{CompiledBinding EventPath}"
|
||||||
ShowFullPath="{CompiledBinding ShowFullPaths.Value}"
|
ShowFullPath="{CompiledBinding ShowFullPaths.Value}"
|
||||||
IsEventPicker="True"/>
|
IsEventPicker="True" />
|
||||||
|
|
||||||
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
|
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
|
||||||
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedTriggerMode}">
|
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedTriggerMode}">
|
||||||
|
|||||||
@ -6,7 +6,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.DisplayCondition.ConditionTypes.PlayOnceConditionView">
|
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.PlayOnceConditionView">
|
||||||
<DockPanel VerticalAlignment="Top" Margin="0 5">
|
<DockPanel VerticalAlignment="Top" Margin="0 5">
|
||||||
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0"/>
|
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0" />
|
||||||
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||||
TextWrapping="Wrap">
|
TextWrapping="Wrap">
|
||||||
Every segment of the timeline is played once.
|
Every segment of the timeline is played once.
|
||||||
|
|||||||
@ -13,19 +13,19 @@
|
|||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Plus" />
|
<avalonia:MaterialIcon Kind="Plus" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
<MenuItem Header="Folder" Command="{Binding AddFolder}">
|
<MenuItem Header="Folder" Command="{CompiledBinding AddFolder}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Folder" />
|
<avalonia:MaterialIcon Kind="Folder" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Layer" Command="{Binding AddLayer}">
|
<MenuItem Header="Layer" Command="{CompiledBinding AddLayer}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Layers" />
|
<avalonia:MaterialIcon Kind="Layers" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="View Properties" Command="{Binding ViewProperties}">
|
<MenuItem Header="View Properties" Command="{CompiledBinding ViewProperties}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Settings" />
|
<avalonia:MaterialIcon Kind="Settings" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
@ -40,112 +40,93 @@
|
|||||||
<avalonia:MaterialIcon Kind="Magic" />
|
<avalonia:MaterialIcon Kind="Magic" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Suspend Profile" IsSelected="{CompiledBinding IsSuspended}">
|
<MenuItem Header="Suspend Profile" Command="{CompiledBinding ToggleSuspended}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox BorderThickness="0"
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding IsSuspended}" />
|
||||||
IsHitTestVisible="False"
|
|
||||||
IsChecked="{CompiledBinding IsSuspended}"/>
|
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Export Profile" Command="{Binding ExportProfile}">
|
<MenuItem Header="Export Profile" Command="{CompiledBinding ExportProfile}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Export" />
|
<avalonia:MaterialIcon Kind="Export" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Duplicate Profile" Command="{Binding DuplicateProfile}">
|
<MenuItem Header="Duplicate Profile" Command="{CompiledBinding DuplicateProfile}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Delete Profile" Command="{Binding DeleteProfile}">
|
<MenuItem Header="Delete Profile" Command="{CompiledBinding DeleteProfile}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Trash" />
|
<avalonia:MaterialIcon Kind="Trash" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Edit" SubmenuOpened="MenuItem_OnSubmenuOpened">
|
<MenuItem Header="_Edit" SubmenuOpened="MenuItem_OnSubmenuOpened">
|
||||||
<MenuItem Header="_Undo"
|
<MenuItem Header="_Undo" Command="{CompiledBinding History.Undo}" InputGesture="Ctrl+Z">
|
||||||
Command="{Binding History.Undo}"
|
|
||||||
HotKey="Ctrl+Z"
|
|
||||||
InputGesture="Ctrl+Z">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Undo" />
|
<avalonia:MaterialIcon Kind="Undo" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Redo"
|
<MenuItem Header="_Redo" Command="{CompiledBinding History.Redo}" InputGesture="Ctrl+Y">
|
||||||
Command="{Binding History.Redo}"
|
|
||||||
HotKey="Ctrl+Y"
|
|
||||||
InputGesture="Ctrl+Y">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Redo" />
|
<avalonia:MaterialIcon Kind="Redo" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="_Duplicate"
|
<MenuItem Header="_Duplicate" Command="{Binding Duplicate}" InputGesture="Ctrl+D">
|
||||||
Command="{Binding Duplicate}"
|
|
||||||
HotKey="Ctrl+D"
|
|
||||||
IsEnabled="{Binding HasSelectedElement}">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Copy"
|
<MenuItem Header="_Copy" Command="{Binding Copy}" InputGesture="Ctrl+C">
|
||||||
Command="{Binding Copy}"
|
|
||||||
HotKey="Ctrl+C"
|
|
||||||
IsEnabled="{Binding HasSelectedElement}">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="ContentCopy" />
|
<avalonia:MaterialIcon Kind="ContentCopy" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Paste"
|
<MenuItem Header="_Paste" Command="{Binding Paste}" InputGesture="Ctrl+V">
|
||||||
Command="{Binding Paste}"
|
|
||||||
HotKey="Ctrl+V">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIconExt Kind="ContentPaste" />
|
<avalonia:MaterialIconExt Kind="ContentPaste" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Run">
|
<MenuItem Header="_Run">
|
||||||
<MenuItem Header="_Switch run mode"
|
<MenuItem Header="_Switch run mode" Command="{CompiledBinding ToggleSuspendedEditing}" InputGesture="F5">
|
||||||
Command="{Binding ToggleSuspend}"
|
|
||||||
HotKey="F5">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="SwapHorizontal" />
|
<avalonia:MaterialIcon Kind="SwapHorizontal" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Run Profile on Focus Loss"
|
<MenuItem Header="Switch Run Mode on Focus Loss"
|
||||||
ToolTip.Tip="If enabled, run mode is set to normal on focus loss"
|
ToolTip.Tip="If enabled, run mode is set to normal on focus loss"
|
||||||
HotKey="Shift+F5">
|
InputGesture="Shift+F5"
|
||||||
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
|
CommandParameter="{CompiledBinding AutoSuspend}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox BorderThickness="0"
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AutoSuspend.Value}" />
|
||||||
IsHitTestVisible="False"
|
|
||||||
IsChecked="{Binding StopOnFocusLoss.Value}" />
|
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Options">
|
<MenuItem Header="_Options">
|
||||||
<MenuItem Header="Focus Selected Layer"
|
<MenuItem Header="Focus Selected Layer" ToolTip.Tip="If enabled, displays only the layer you currently have selected"
|
||||||
ToolTip.Tip="If enabled, displays only the layer you currently have selected"
|
|
||||||
Command="{CompiledBinding ToggleBooleanSetting}"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
CommandParameter="{CompiledBinding FocusSelectedLayer}">
|
CommandParameter="{CompiledBinding FocusSelectedLayer}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding FocusSelectedLayer.Value}"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding FocusSelectedLayer.Value}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Display Data Model Values"
|
<MenuItem Header="Display Data Model Values"
|
||||||
Command="{CompiledBinding ToggleBooleanSetting}"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
CommandParameter="{CompiledBinding ShowDataModelValues}">
|
CommandParameter="{CompiledBinding ShowDataModelValues}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowDataModelValues.Value}"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowDataModelValues.Value}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Display Full Condition Paths"
|
<MenuItem Header="Display Full Condition Paths"
|
||||||
Command="{CompiledBinding ToggleBooleanSetting}"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
CommandParameter="{CompiledBinding ShowFullPaths}">
|
CommandParameter="{CompiledBinding ShowFullPaths}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowFullPaths.Value}"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowFullPaths.Value}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Always Display Cable Values"
|
<MenuItem Header="Always Display Cable Values"
|
||||||
@ -153,7 +134,7 @@
|
|||||||
Command="{CompiledBinding ToggleBooleanSetting}"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
CommandParameter="{CompiledBinding AlwaysShowValues}">
|
CommandParameter="{CompiledBinding AlwaysShowValues}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysShowValues.Value}"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysShowValues.Value}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Apply All Data Bindings During Edit"
|
<MenuItem Header="Apply All Data Bindings During Edit"
|
||||||
@ -161,54 +142,54 @@
|
|||||||
Command="{CompiledBinding ToggleBooleanSetting}"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
CommandParameter="{CompiledBinding AlwaysApplyDataBindings}">
|
CommandParameter="{CompiledBinding AlwaysApplyDataBindings}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysApplyDataBindings.Value}"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysApplyDataBindings.Value}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Help">
|
<MenuItem Header="_Help">
|
||||||
<MenuItem Header="Artemis Wiki" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/">
|
<MenuItem Header="Artemis Wiki" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="BookEdit" />
|
<avalonia:MaterialIcon Kind="BookEdit" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Editor" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/en/guides/user/profiles">
|
<MenuItem Header="Editor" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/en/guides/user/profiles">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Edit" />
|
<avalonia:MaterialIcon Kind="Edit" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Layers" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/layers">
|
<MenuItem Header="Layers" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/layers">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Layers" />
|
<avalonia:MaterialIcon Kind="Layers" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Display Conditions" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/conditions">
|
<MenuItem Header="Display Conditions" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/conditions">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="NotEqual" />
|
<avalonia:MaterialIcon Kind="NotEqual" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Timeline" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/timeline">
|
<MenuItem Header="Timeline" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/timeline">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Stopwatch" />
|
<avalonia:MaterialIcon Kind="Stopwatch" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Data Bindings" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/data-bindings">
|
<MenuItem Header="Data Bindings" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/data-bindings">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="VectorLink" />
|
<avalonia:MaterialIcon Kind="VectorLink" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Scripting" Command="{Binding OpenUrl}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/scripting">
|
<MenuItem Header="Scripting" Command="{CompiledBinding OpenUri}" CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/scripting">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="CodeJson" />
|
<avalonia:MaterialIcon Kind="CodeJson" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Report a Bug" Command="{Binding OpenUrl}" CommandParameter="https://github.com/Artemis-RGB/Artemis/issues">
|
<MenuItem Header="Report a Bug" Command="{CompiledBinding OpenUri}" CommandParameter="https://github.com/Artemis-RGB/Artemis/issues">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Github" />
|
<avalonia:MaterialIcon Kind="Github" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Get Help on Discord" Command="{Binding OpenUrl}" CommandParameter="https://discord.gg/S3MVaC9">
|
<MenuItem Header="Get Help on Discord" Command="{CompiledBinding OpenUri}" CommandParameter="https://discord.gg/S3MVaC9">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Discord" />
|
<avalonia:MaterialIcon Kind="Discord" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
|
|||||||
@ -2,10 +2,10 @@ using Avalonia.Interactivity;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.MenuBar
|
namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
||||||
|
|
||||||
|
public class MenuBarView : ReactiveUserControl<MenuBarViewModel>
|
||||||
{
|
{
|
||||||
public partial class MenuBarView : ReactiveUserControl<MenuBarViewModel>
|
|
||||||
{
|
|
||||||
public MenuBarView()
|
public MenuBarView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -18,7 +18,5 @@ namespace Artemis.UI.Screens.ProfileEditor.MenuBar
|
|||||||
|
|
||||||
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,31 +1,50 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Screens.Sidebar;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
|
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
||||||
|
|
||||||
public class MenuBarViewModel : ActivatableViewModelBase
|
public class MenuBarViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
private ProfileEditorHistory? _history;
|
private ProfileEditorHistory? _history;
|
||||||
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
||||||
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
||||||
|
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
||||||
|
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
|
||||||
|
|
||||||
public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService)
|
public MenuBarViewModel(ILogger logger, IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService, IWindowService windowService)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
_windowService = windowService;
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
profileEditorService.History.Subscribe(history => History = history).DisposeWith(d);
|
profileEditorService.History.Subscribe(history => History = history).DisposeWith(d);
|
||||||
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
|
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
|
||||||
|
_profileElement = profileEditorService.ProfileElement.ToProperty(this, vm => vm.ProfileElement).DisposeWith(d);
|
||||||
|
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
|
||||||
_isSuspended = profileEditorService.ProfileConfiguration
|
_isSuspended = profileEditorService.ProfileConfiguration
|
||||||
.Select(p => p?.WhenAnyValue(c => c.IsSuspended) ?? Observable.Never<bool>())
|
.Select(p => p?.WhenAnyValue(c => c.IsSuspended) ?? Observable.Never<bool>())
|
||||||
.Switch()
|
.Switch()
|
||||||
@ -33,17 +52,35 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddFolder = ReactiveCommand.Create(ExecuteAddFolder);
|
||||||
|
AddLayer = ReactiveCommand.Create(ExecuteAddLayer);
|
||||||
|
ViewProperties = ReactiveCommand.CreateFromTask(ExecuteViewProperties, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
DeleteProfile = ReactiveCommand.CreateFromTask(ExecuteDeleteProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
DuplicateProfile = ReactiveCommand.Create(ExecuteDuplicateProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
ToggleSuspendedEditing = ReactiveCommand.Create(ExecuteToggleSuspendedEditing);
|
||||||
ToggleBooleanSetting = ReactiveCommand.Create<PluginSetting<bool>>(ExecuteToggleBooleanSetting);
|
ToggleBooleanSetting = ReactiveCommand.Create<PluginSetting<bool>>(ExecuteToggleBooleanSetting);
|
||||||
|
OpenUri = ReactiveCommand.CreateFromTask<string>(ExecuteOpenUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteToggleBooleanSetting(PluginSetting<bool> setting)
|
public ReactiveCommand<Unit, Unit> AddFolder { get; }
|
||||||
{
|
public ReactiveCommand<Unit, Unit> AddLayer { get; }
|
||||||
setting.Value = !setting.Value;
|
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
||||||
setting.Save();
|
public ReactiveCommand<Unit, Unit> ViewProperties { get; }
|
||||||
}
|
public ReactiveCommand<Unit, Unit> DeleteProfile { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ExportProfile { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> DuplicateProfile { get; }
|
||||||
public ReactiveCommand<PluginSetting<bool>, Unit> ToggleBooleanSetting { get; }
|
public ReactiveCommand<PluginSetting<bool>, Unit> ToggleBooleanSetting { get; }
|
||||||
|
public ReactiveCommand<string, Unit> OpenUri { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ToggleSuspendedEditing { get; }
|
||||||
|
|
||||||
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
||||||
|
public RenderProfileElement? ProfileElement => _profileElement?.Value;
|
||||||
|
public bool IsSuspended => _isSuspended?.Value ?? false;
|
||||||
|
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
|
||||||
|
|
||||||
|
public PluginSetting<bool> AutoSuspend => _settingsService.GetSetting("ProfileEditor.AutoSuspend", true);
|
||||||
public PluginSetting<bool> FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false);
|
public PluginSetting<bool> FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false);
|
||||||
public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||||
public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
|
public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
|
||||||
@ -56,16 +93,113 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
set => RaiseAndSetIfChanged(ref _history, value);
|
set => RaiseAndSetIfChanged(ref _history, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSuspended
|
private void ExecuteAddFolder()
|
||||||
{
|
{
|
||||||
get => _isSuspended?.Value ?? false;
|
if (ProfileConfiguration?.Profile == null)
|
||||||
set
|
return;
|
||||||
|
|
||||||
|
RenderProfileElement target = ProfileElement ?? ProfileConfiguration.Profile.GetRootFolder();
|
||||||
|
_profileEditorService.CreateAndAddFolder(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteAddLayer()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration?.Profile == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RenderProfileElement target = ProfileElement ?? ProfileConfiguration.Profile.GetRootFolder();
|
||||||
|
_profileEditorService.CreateAndAddLayer(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteViewProperties()
|
||||||
{
|
{
|
||||||
if (ProfileConfiguration == null)
|
if (ProfileConfiguration == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ProfileConfiguration.IsSuspended = value;
|
await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
|
||||||
|
("profileCategory", ProfileConfiguration.Category),
|
||||||
|
("profileConfiguration", ProfileConfiguration)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleSuspended()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProfileConfiguration.IsSuspended = !ProfileConfiguration.IsSuspended;
|
||||||
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteDeleteProfile()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration == null)
|
||||||
|
return;
|
||||||
|
if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ProfileConfiguration.IsBeingEdited)
|
||||||
|
_profileEditorService.ChangeCurrentProfileConfiguration(null);
|
||||||
|
_profileService.RemoveProfileConfiguration(ProfileConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteExportProfile()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Might not cover everything but then the dialog will complain and that's good enough
|
||||||
|
string fileName = Path.GetInvalidFileNameChars().Aggregate(ProfileConfiguration.Name, (current, c) => current.Replace(c, '-'));
|
||||||
|
string? result = await _windowService.CreateSaveFileDialog()
|
||||||
|
.HavingFilter(f => f.WithExtension("json").WithName("Artemis profile"))
|
||||||
|
.WithInitialFileName(fileName)
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
|
||||||
|
string json = JsonConvert.SerializeObject(export, IProfileService.ExportSettings);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await File.WriteAllTextAsync(result, json);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_windowService.ShowExceptionDialog("Failed to export profile", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteDuplicateProfile()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
|
||||||
|
_profileService.ImportProfile(ProfileConfiguration.Category, export, true, false, "copy");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleSuspendedEditing()
|
||||||
|
{
|
||||||
|
_profileEditorService.ChangeSuspendedEditing(!SuspendedEditing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleBooleanSetting(PluginSetting<bool> setting)
|
||||||
|
{
|
||||||
|
setting.Value = !setting.Value;
|
||||||
|
setting.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteOpenUri(string uri)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo(uri) {UseShellExecute = true, Verb = "open"});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Failed to open URL");
|
||||||
|
await _windowService.ShowConfirmContentDialog("Failed to open URL", "We couldn't open the URL for you, check the logs for more details", "Confirm", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,6 +60,6 @@
|
|||||||
|
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Classes="h4" Text="{CompiledBinding FormattedCurrentTime, FallbackValue=00.000}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0"/>
|
<TextBlock Classes="h4" Text="{CompiledBinding FormattedCurrentTime, FallbackValue=00.000}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Playback
|
namespace Artemis.UI.Screens.ProfileEditor.Playback;
|
||||||
|
|
||||||
|
public class PlaybackView : ReactiveUserControl<PlaybackViewModel>
|
||||||
{
|
{
|
||||||
public partial class PlaybackView : ReactiveUserControl<PlaybackViewModel>
|
|
||||||
{
|
|
||||||
public PlaybackView()
|
public PlaybackView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -14,5 +14,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Playback
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -14,14 +14,14 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
private RenderProfileElement? _profileElement;
|
|
||||||
private ObservableAsPropertyHelper<TimeSpan>? _currentTime;
|
private ObservableAsPropertyHelper<TimeSpan>? _currentTime;
|
||||||
private ObservableAsPropertyHelper<string?>? _formattedCurrentTime;
|
private ObservableAsPropertyHelper<string?>? _formattedCurrentTime;
|
||||||
private ObservableAsPropertyHelper<bool>? _playing;
|
|
||||||
private bool _repeating;
|
|
||||||
private bool _repeatTimeline;
|
|
||||||
private bool _repeatSegment;
|
|
||||||
private DateTime _lastUpdate;
|
private DateTime _lastUpdate;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _playing;
|
||||||
|
private RenderProfileElement? _profileElement;
|
||||||
|
private bool _repeating;
|
||||||
|
private bool _repeatSegment;
|
||||||
|
private bool _repeatTimeline;
|
||||||
|
|
||||||
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
@ -14,21 +13,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
|||||||
|
|
||||||
public class FolderTreeItemViewModel : TreeItemViewModel
|
public class FolderTreeItemViewModel : TreeItemViewModel
|
||||||
{
|
{
|
||||||
public FolderTreeItemViewModel(TreeItemViewModel? parent,
|
public FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
|
||||||
Folder folder,
|
: base(parent, folder, windowService, profileEditorService, profileEditorVmFactory)
|
||||||
IWindowService windowService,
|
|
||||||
IProfileEditorService profileEditorService,
|
|
||||||
ILayerBrushService layerBrushService,
|
|
||||||
IProfileEditorVmFactory profileEditorVmFactory,
|
|
||||||
IRgbService rgbService)
|
|
||||||
: base(parent, folder, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
|
|
||||||
{
|
{
|
||||||
Folder = folder;
|
Folder = folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Folder Folder { get; }
|
public Folder Folder { get; }
|
||||||
|
|
||||||
|
|
||||||
#region Overrides of TreeItemViewModel
|
#region Overrides of TreeItemViewModel
|
||||||
|
|
||||||
protected override async Task ExecuteDuplicate()
|
protected override async Task ExecuteDuplicate()
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
@ -14,14 +13,8 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
|||||||
|
|
||||||
public class LayerTreeItemViewModel : TreeItemViewModel
|
public class LayerTreeItemViewModel : TreeItemViewModel
|
||||||
{
|
{
|
||||||
public LayerTreeItemViewModel(TreeItemViewModel? parent,
|
public LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
|
||||||
Layer layer,
|
: base(parent, layer, windowService, profileEditorService, profileEditorVmFactory)
|
||||||
IWindowService windowService,
|
|
||||||
IProfileEditorService profileEditorService,
|
|
||||||
IRgbService rgbService,
|
|
||||||
ILayerBrushService layerBrushService,
|
|
||||||
IProfileEditorVmFactory profileEditorVmFactory)
|
|
||||||
: base(parent, layer, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
|
|
||||||
{
|
{
|
||||||
Layer = layer;
|
Layer = layer;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ using System.Linq;
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
@ -18,12 +17,8 @@ public class ProfileTreeViewModel : TreeItemViewModel
|
|||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private TreeItemViewModel? _selectedChild;
|
private TreeItemViewModel? _selectedChild;
|
||||||
|
|
||||||
public ProfileTreeViewModel(IWindowService windowService,
|
public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
|
||||||
IProfileEditorService profileEditorService,
|
: base(null, null, windowService, profileEditorService, profileEditorVmFactory)
|
||||||
ILayerBrushService layerBrushService,
|
|
||||||
IProfileEditorVmFactory profileEditorVmFactory,
|
|
||||||
IRgbService rgbService)
|
|
||||||
: base(null, null, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
|
|
||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
|
|||||||
@ -7,7 +7,6 @@ using System.Reactive.Disposables;
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
|
||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
@ -21,9 +20,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
|||||||
|
|
||||||
public abstract class TreeItemViewModel : ActivatableViewModelBase
|
public abstract class TreeItemViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly ILayerBrushService _layerBrushService;
|
|
||||||
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
|
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
|
||||||
private readonly IRgbService _rgbService;
|
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
protected readonly IProfileEditorService ProfileEditorService;
|
protected readonly IProfileEditorService ProfileEditorService;
|
||||||
private bool _canPaste;
|
private bool _canPaste;
|
||||||
@ -34,16 +31,13 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
private string? _renameValue;
|
private string? _renameValue;
|
||||||
private bool _renaming;
|
private bool _renaming;
|
||||||
|
|
||||||
protected TreeItemViewModel(TreeItemViewModel? parent, ProfileElement? profileElement,
|
protected TreeItemViewModel(TreeItemViewModel? parent,
|
||||||
|
ProfileElement? profileElement,
|
||||||
IWindowService windowService,
|
IWindowService windowService,
|
||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IRgbService rgbService,
|
|
||||||
ILayerBrushService layerBrushService,
|
|
||||||
IProfileEditorVmFactory profileEditorVmFactory)
|
IProfileEditorVmFactory profileEditorVmFactory)
|
||||||
{
|
{
|
||||||
ProfileEditorService = profileEditorService;
|
ProfileEditorService = profileEditorService;
|
||||||
_rgbService = rgbService;
|
|
||||||
_layerBrushService = layerBrushService;
|
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
_profileEditorVmFactory = profileEditorVmFactory;
|
_profileEditorVmFactory = profileEditorVmFactory;
|
||||||
|
|
||||||
@ -126,7 +120,8 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
foreach (IBreakableModel current in broken)
|
foreach (IBreakableModel current in broken)
|
||||||
{
|
{
|
||||||
_windowService.ShowExceptionDialog($"{current.BrokenDisplayName} - {current.BrokenState}", current.BrokenStateException!);
|
_windowService.ShowExceptionDialog($"{current.BrokenDisplayName} - {current.BrokenState}", current.BrokenStateException!);
|
||||||
if (broken.Last() != current)
|
if (broken.Last() == current)
|
||||||
|
continue;
|
||||||
if (!await _windowService.ShowConfirmContentDialog("Broken state", "Do you want to view the next exception?"))
|
if (!await _windowService.ShowConfirmContentDialog("Broken state", "Do you want to view the next exception?"))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -243,30 +238,14 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
private void ExecuteAddFolder()
|
private void ExecuteAddFolder()
|
||||||
{
|
{
|
||||||
if (ProfileElement is Layer targetLayer)
|
if (ProfileElement != null)
|
||||||
ProfileEditorService.ExecuteCommand(new AddProfileElement(new Folder(targetLayer.Parent, targetLayer.Parent.GetNewFolderName()), targetLayer.Parent, targetLayer.Order));
|
ProfileEditorService.CreateAndAddFolder(ProfileElement);
|
||||||
else if (ProfileElement != null)
|
|
||||||
ProfileEditorService.ExecuteCommand(new AddProfileElement(new Folder(ProfileElement, ProfileElement.GetNewFolderName()), ProfileElement, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteAddLayer()
|
private void ExecuteAddLayer()
|
||||||
{
|
{
|
||||||
if (ProfileElement is Layer targetLayer)
|
if (ProfileElement != null)
|
||||||
{
|
ProfileEditorService.CreateAndAddLayer(ProfileElement);
|
||||||
Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName());
|
|
||||||
_layerBrushService.ApplyDefaultBrush(layer);
|
|
||||||
|
|
||||||
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
|
|
||||||
ProfileEditorService.ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order));
|
|
||||||
}
|
|
||||||
else if (ProfileElement != null)
|
|
||||||
{
|
|
||||||
Layer layer = new(ProfileElement, ProfileElement.GetNewLayerName());
|
|
||||||
_layerBrushService.ApplyDefaultBrush(layer);
|
|
||||||
|
|
||||||
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
|
|
||||||
ProfileEditorService.ExecuteCommand(new AddProfileElement(layer, ProfileElement, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void UpdateCanPaste(bool isFlyoutOpen)
|
private async void UpdateCanPaste(bool isFlyoutOpen)
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Command="{Binding OpenEditor}">
|
Command="{Binding OpenEditor}">
|
||||||
<avalonia:MaterialIcon Kind="OpenInNew"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="OpenInNew" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.DataBinding
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
||||||
|
|
||||||
|
public class DataBindingView : ReactiveUserControl<DataBindingViewModel>
|
||||||
{
|
{
|
||||||
public partial class DataBindingView : ReactiveUserControl<DataBindingViewModel>
|
|
||||||
{
|
|
||||||
public DataBindingView()
|
public DataBindingView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -14,5 +14,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.DataBinding
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
x:DataType="dialogs:AddEffectViewModel"
|
x:DataType="dialogs:AddEffectViewModel"
|
||||||
Width="500">
|
Width="500">
|
||||||
<Grid RowDefinitions="Auto,*">
|
<Grid RowDefinitions="Auto,*">
|
||||||
<TextBox Name="SearchBox" Text="{CompiledBinding SearchText}" Margin="0 0 0 15" Watermark="Search"></TextBox>
|
<TextBox Name="SearchBox" Text="{CompiledBinding SearchText}" Margin="0 0 0 15" Watermark="Search" />
|
||||||
<ListBox Name="EffectDescriptorsList"
|
<ListBox Name="EffectDescriptorsList"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Items="{CompiledBinding LayerEffectDescriptors}"
|
Items="{CompiledBinding LayerEffectDescriptors}"
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<StackPanel VerticalAlignment="Center"
|
<StackPanel VerticalAlignment="Center"
|
||||||
Spacing="20"
|
Spacing="20"
|
||||||
IsVisible="{CompiledBinding !LayerEffectDescriptors.Count}">
|
IsVisible="{CompiledBinding !LayerEffectDescriptors.Count}">
|
||||||
<avalonia:MaterialIcon Kind="CloseCircle" Width="32" Height="32"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="CloseCircle" Width="32" Height="32" />
|
||||||
<TextBlock Classes="h5" TextAlignment="Center">None of the effects match your search</TextBlock>
|
<TextBlock Classes="h5" TextAlignment="Center">None of the effects match your search</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -14,8 +14,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
|||||||
|
|
||||||
public class AddEffectViewModel : ContentDialogViewModelBase
|
public class AddEffectViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
private readonly RenderProfileElement _renderProfileElement;
|
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
|
private readonly RenderProfileElement _renderProfileElement;
|
||||||
private string? _searchText;
|
private string? _searchText;
|
||||||
|
|
||||||
public AddEffectViewModel(RenderProfileElement renderProfileElement, IProfileEditorService profileEditorService, ILayerEffectService layerEffectService)
|
public AddEffectViewModel(RenderProfileElement renderProfileElement, IProfileEditorService profileEditorService, ILayerEffectService layerEffectService)
|
||||||
@ -39,7 +39,7 @@ public class AddEffectViewModel : ContentDialogViewModelBase
|
|||||||
public string? SearchText
|
public string? SearchText
|
||||||
{
|
{
|
||||||
get => _searchText;
|
get => _searchText;
|
||||||
set => this.RaiseAndSetIfChanged(ref _searchText, value);
|
set => RaiseAndSetIfChanged(ref _searchText, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddLayerEffect(LayerEffectDescriptor descriptor)
|
public void AddLayerEffect(LayerEffectDescriptor descriptor)
|
||||||
@ -59,4 +59,3 @@ public class AddEffectViewModel : ContentDialogViewModelBase
|
|||||||
data.Description.Contains(search, StringComparison.InvariantCultureIgnoreCase);
|
data.Description.Contains(search, StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
xmlns:controls="clr-namespace:Artemis.UI.Controls"
|
xmlns:controls="clr-namespace:Artemis.UI.Controls"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
|
||||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="350"
|
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="350"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.PropertiesView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.PropertiesView"
|
||||||
x:DataType="local:PropertiesViewModel">
|
x:DataType="local:PropertiesViewModel">
|
||||||
@ -13,7 +12,7 @@
|
|||||||
<StyleInclude Source="/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml" />
|
<StyleInclude Source="/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml" />
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Name="ContainerGrid">
|
<Grid Name="ContainerGrid">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -89,8 +88,7 @@
|
|||||||
StartPoint="0,0"
|
StartPoint="0,0"
|
||||||
EndPoint="{CompiledBinding #ContainerGrid.Bounds.BottomLeft}"
|
EndPoint="{CompiledBinding #ContainerGrid.Bounds.BottomLeft}"
|
||||||
StrokeThickness="2"
|
StrokeThickness="2"
|
||||||
Stroke="{DynamicResource SystemAccentColorLight1}">
|
Stroke="{DynamicResource SystemAccentColorLight1}" />
|
||||||
</Line>
|
|
||||||
|
|
||||||
<Line Name="StartSegmentLine"
|
<Line Name="StartSegmentLine"
|
||||||
Canvas.Left="{CompiledBinding TimelineViewModel.StartSegmentViewModel.EndX}"
|
Canvas.Left="{CompiledBinding TimelineViewModel.StartSegmentViewModel.EndX}"
|
||||||
@ -100,8 +98,7 @@
|
|||||||
StrokeThickness="2"
|
StrokeThickness="2"
|
||||||
Stroke="{DynamicResource SystemAccentColorLight1}"
|
Stroke="{DynamicResource SystemAccentColorLight1}"
|
||||||
StrokeDashArray="6,2"
|
StrokeDashArray="6,2"
|
||||||
Opacity="0.5">
|
Opacity="0.5" />
|
||||||
</Line>
|
|
||||||
<Line Name="MainSegmentLine"
|
<Line Name="MainSegmentLine"
|
||||||
Canvas.Left="{CompiledBinding TimelineViewModel.MainSegmentViewModel.EndX}"
|
Canvas.Left="{CompiledBinding TimelineViewModel.MainSegmentViewModel.EndX}"
|
||||||
IsVisible="{CompiledBinding !TimelineViewModel.MainSegmentViewModel.ShowAddMain}"
|
IsVisible="{CompiledBinding !TimelineViewModel.MainSegmentViewModel.ShowAddMain}"
|
||||||
@ -110,8 +107,7 @@
|
|||||||
StrokeThickness="2"
|
StrokeThickness="2"
|
||||||
Stroke="{DynamicResource SystemAccentColorLight1}"
|
Stroke="{DynamicResource SystemAccentColorLight1}"
|
||||||
StrokeDashArray="6,2"
|
StrokeDashArray="6,2"
|
||||||
Opacity="0.5">
|
Opacity="0.5" />
|
||||||
</Line>
|
|
||||||
<Line Name="EndSegmentLine"
|
<Line Name="EndSegmentLine"
|
||||||
Canvas.Left="{CompiledBinding TimelineViewModel.EndSegmentViewModel.EndX}"
|
Canvas.Left="{CompiledBinding TimelineViewModel.EndSegmentViewModel.EndX}"
|
||||||
IsVisible="{CompiledBinding !TimelineViewModel.MainSegmentViewModel.ShowAddEnd}"
|
IsVisible="{CompiledBinding !TimelineViewModel.MainSegmentViewModel.ShowAddEnd}"
|
||||||
@ -120,8 +116,7 @@
|
|||||||
StrokeThickness="2"
|
StrokeThickness="2"
|
||||||
Stroke="{DynamicResource SystemAccentColorLight1}"
|
Stroke="{DynamicResource SystemAccentColorLight1}"
|
||||||
StrokeDashArray="6,2"
|
StrokeDashArray="6,2"
|
||||||
Opacity="0.5">
|
Opacity="0.5" />
|
||||||
</Line>
|
|
||||||
|
|
||||||
<!-- Timeline segments -->
|
<!-- Timeline segments -->
|
||||||
<ContentControl Canvas.Left="{CompiledBinding TimelineViewModel.EndSegmentViewModel.StartX}"
|
<ContentControl Canvas.Left="{CompiledBinding TimelineViewModel.EndSegmentViewModel.StartX}"
|
||||||
@ -142,8 +137,7 @@
|
|||||||
PointerReleased="TimelineCaret_OnPointerReleased"
|
PointerReleased="TimelineCaret_OnPointerReleased"
|
||||||
PointerMoved="TimelineCaret_OnPointerMoved"
|
PointerMoved="TimelineCaret_OnPointerMoved"
|
||||||
Points="-8,0 -8,8 0,20, 8,8 8,0"
|
Points="-8,0 -8,8 0,20, 8,8 8,0"
|
||||||
Fill="{DynamicResource SystemAccentColorLight1}">
|
Fill="{DynamicResource SystemAccentColorLight1}" />
|
||||||
</Polygon>
|
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1"
|
<ScrollViewer Grid.Row="1"
|
||||||
|
|||||||
@ -15,10 +15,8 @@ using Artemis.UI.Screens.ProfileEditor.Playback;
|
|||||||
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
||||||
using Artemis.UI.Screens.Sidebar;
|
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
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 ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
@ -28,11 +26,11 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly Dictionary<LayerPropertyGroup, PropertyGroupViewModel> _cachedPropertyViewModels;
|
private readonly Dictionary<LayerPropertyGroup, PropertyGroupViewModel> _cachedPropertyViewModels;
|
||||||
private readonly IDataBindingVmFactory _dataBindingVmFactory;
|
private readonly IDataBindingVmFactory _dataBindingVmFactory;
|
||||||
private readonly IWindowService _windowService;
|
|
||||||
private readonly ILayerEffectService _layerEffectService;
|
private readonly ILayerEffectService _layerEffectService;
|
||||||
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
|
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
private DataBindingViewModel? _backgroundDataBindingViewModel;
|
private DataBindingViewModel? _backgroundDataBindingViewModel;
|
||||||
private DataBindingViewModel? _dataBindingViewModel;
|
private DataBindingViewModel? _dataBindingViewModel;
|
||||||
private ObservableAsPropertyHelper<ILayerProperty?>? _layerProperty;
|
private ObservableAsPropertyHelper<ILayerProperty?>? _layerProperty;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes;
|
||||||
|
|
||||||
|
public class TimelineEasingView : UserControl
|
||||||
{
|
{
|
||||||
public partial class TimelineEasingView : UserControl
|
|
||||||
{
|
|
||||||
public TimelineEasingView()
|
public TimelineEasingView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -14,5 +14,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -44,8 +44,8 @@
|
|||||||
</Template>
|
</Template>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
<Setter Property="Command" Value="{Binding $parent[UserControl].DataContext.SelectEasingFunction}"></Setter>
|
<Setter Property="Command" Value="{Binding $parent[UserControl].DataContext.SelectEasingFunction}" />
|
||||||
<Setter Property="CommandParameter" Value="{Binding EasingFunction}"></Setter>
|
<Setter Property="CommandParameter" Value="{Binding EasingFunction}" />
|
||||||
</Style>
|
</Style>
|
||||||
</MenuItem.Styles>
|
</MenuItem.Styles>
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
|
|||||||
@ -8,9 +8,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes;
|
|||||||
|
|
||||||
public class TimelineKeyframeView : ReactiveUserControl<ITimelineKeyframeViewModel>
|
public class TimelineKeyframeView : ReactiveUserControl<ITimelineKeyframeViewModel>
|
||||||
{
|
{
|
||||||
|
private bool _moved;
|
||||||
private TimelinePropertyView? _timelinePropertyView;
|
private TimelinePropertyView? _timelinePropertyView;
|
||||||
private TimelineView? _timelineView;
|
private TimelineView? _timelineView;
|
||||||
private bool _moved;
|
|
||||||
|
|
||||||
public TimelineKeyframeView()
|
public TimelineKeyframeView()
|
||||||
{
|
{
|
||||||
@ -70,7 +70,9 @@ public class TimelineKeyframeView : ReactiveUserControl<ITimelineKeyframeViewMod
|
|||||||
|
|
||||||
// Select the keyframe if the user didn't move
|
// Select the keyframe if the user didn't move
|
||||||
if (!_moved)
|
if (!_moved)
|
||||||
|
{
|
||||||
ViewModel.Select(e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
ViewModel.Select(e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TimeSpan time = ViewModel.GetTimeSpanAtPosition(e.GetPosition(_timelinePropertyView).X);
|
TimeSpan time = ViewModel.GetTimeSpanAtPosition(e.GetPosition(_timelinePropertyView).X);
|
||||||
|
|||||||
@ -15,10 +15,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes;
|
|||||||
public class TimelineKeyframeViewModel<T> : ActivatableViewModelBase, ITimelineKeyframeViewModel
|
public class TimelineKeyframeViewModel<T> : ActivatableViewModelBase, ITimelineKeyframeViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _isSelected;
|
||||||
|
private string _timestamp;
|
||||||
|
|
||||||
private double _x;
|
private double _x;
|
||||||
private string _timestamp;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _isSelected;
|
|
||||||
|
|
||||||
public TimelineKeyframeViewModel(LayerPropertyKeyframe<T> layerPropertyKeyframe, IProfileEditorService profileEditorService)
|
public TimelineKeyframeViewModel(LayerPropertyKeyframe<T> layerPropertyKeyframe, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
@ -56,16 +56,16 @@ public class TimelineKeyframeViewModel<T> : ActivatableViewModelBase, ITimelineK
|
|||||||
set => RaiseAndSetIfChanged(ref _timestamp, value);
|
set => RaiseAndSetIfChanged(ref _timestamp, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSelected => _isSelected?.Value ?? false;
|
|
||||||
public TimeSpan Position => LayerPropertyKeyframe.Position;
|
|
||||||
public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe;
|
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
X = _pixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds;
|
X = _pixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds;
|
||||||
Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}";
|
Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSelected => _isSelected?.Value ?? false;
|
||||||
|
public TimeSpan Position => LayerPropertyKeyframe.Position;
|
||||||
|
public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Select(bool expand, bool toggle)
|
public void Select(bool expand, bool toggle)
|
||||||
{
|
{
|
||||||
@ -165,4 +165,3 @@ public class TimelineKeyframeViewModel<T> : ActivatableViewModelBase, ITimelineK
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
||||||
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
||||||
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
||||||
ToolTip.Tip="{CompiledBinding EndTimestamp}"/>
|
ToolTip.Tip="{CompiledBinding EndTimestamp}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -4,10 +4,10 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
||||||
|
|
||||||
|
public class EndSegmentView : ReactiveUserControl<EndSegmentViewModel>
|
||||||
{
|
{
|
||||||
public partial class EndSegmentView : ReactiveUserControl<EndSegmentViewModel>
|
|
||||||
{
|
|
||||||
private readonly Rectangle _keyframeDragAnchor;
|
private readonly Rectangle _keyframeDragAnchor;
|
||||||
private double _dragOffset;
|
private double _dragOffset;
|
||||||
|
|
||||||
@ -46,5 +46,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
|||||||
e.Pointer.Capture(null);
|
e.Pointer.Capture(null);
|
||||||
ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset);
|
ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
@ -13,14 +11,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
|||||||
public class EndSegmentViewModel : TimelineSegmentViewModel
|
public class EndSegmentViewModel : TimelineSegmentViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private RenderProfileElement? _profileElement;
|
private readonly ObservableAsPropertyHelper<double> _width;
|
||||||
private int _pixelsPerSecond;
|
|
||||||
private TimeSpan _time;
|
|
||||||
private ObservableAsPropertyHelper<double>? _start;
|
|
||||||
private ObservableAsPropertyHelper<double>? _end;
|
private ObservableAsPropertyHelper<double>? _end;
|
||||||
private ObservableAsPropertyHelper<string?>? _endTimestamp;
|
private ObservableAsPropertyHelper<string?>? _endTimestamp;
|
||||||
private readonly ObservableAsPropertyHelper<double> _width;
|
|
||||||
private TimeSpan _initialLength;
|
private TimeSpan _initialLength;
|
||||||
|
private int _pixelsPerSecond;
|
||||||
|
private RenderProfileElement? _profileElement;
|
||||||
|
private ObservableAsPropertyHelper<double>? _start;
|
||||||
|
private TimeSpan _time;
|
||||||
|
|
||||||
|
|
||||||
public EndSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
|
public EndSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
|
||||||
@ -59,6 +57,7 @@ public class EndSegmentViewModel : TimelineSegmentViewModel
|
|||||||
public override double StartX => _start?.Value ?? 0;
|
public override double StartX => _start?.Value ?? 0;
|
||||||
public override TimeSpan End => _profileElement?.Timeline.EndSegmentEndPosition ?? TimeSpan.Zero;
|
public override TimeSpan End => _profileElement?.Timeline.EndSegmentEndPosition ?? TimeSpan.Zero;
|
||||||
public override double EndX => _end?.Value ?? 0;
|
public override double EndX => _end?.Value ?? 0;
|
||||||
|
|
||||||
public override TimeSpan Length
|
public override TimeSpan Length
|
||||||
{
|
{
|
||||||
get => _profileElement?.Timeline.EndSegmentLength ?? TimeSpan.Zero;
|
get => _profileElement?.Timeline.EndSegmentLength ?? TimeSpan.Zero;
|
||||||
|
|||||||
@ -67,7 +67,7 @@
|
|||||||
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
||||||
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
||||||
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
||||||
ToolTip.Tip="{CompiledBinding EndTimestamp}"/>
|
ToolTip.Tip="{CompiledBinding EndTimestamp}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -4,10 +4,10 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
||||||
|
|
||||||
|
public class MainSegmentView : ReactiveUserControl<MainSegmentViewModel>
|
||||||
{
|
{
|
||||||
public partial class MainSegmentView : ReactiveUserControl<MainSegmentViewModel>
|
|
||||||
{
|
|
||||||
private readonly Rectangle _keyframeDragAnchor;
|
private readonly Rectangle _keyframeDragAnchor;
|
||||||
private double _dragOffset;
|
private double _dragOffset;
|
||||||
|
|
||||||
@ -58,5 +58,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
|||||||
private void KeyframeDragStartAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
private void KeyframeDragStartAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -6,23 +6,22 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
|
|
||||||
<Style Selector="ContentControl.segment-content-control">
|
<Style Selector="ContentControl.segment-content-control" />
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style Selector="Border.segment-container">
|
<Style Selector="Border.segment-container">
|
||||||
<Setter Property="Height" Value="18"></Setter>
|
<Setter Property="Height" Value="18" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Rectangle.resize-visual">
|
<Style Selector="Rectangle.resize-visual">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColorLight2}"/>
|
<Setter Property="Fill" Value="{DynamicResource SystemAccentColorLight2}" />
|
||||||
<Setter Property="Width" Value="4"/>
|
<Setter Property="Width" Value="4" />
|
||||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Rectangle.resize-anchor">
|
<Style Selector="Rectangle.resize-anchor">
|
||||||
<Setter Property="Fill" Value="Transparent"/>
|
<Setter Property="Fill" Value="Transparent" />
|
||||||
<Setter Property="Width" Value="10"/>
|
<Setter Property="Width" Value="10" />
|
||||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
<Setter Property="Cursor" Value="SizeWestEast"/>
|
<Setter Property="Cursor" Value="SizeWestEast" />
|
||||||
</Style>
|
</Style>
|
||||||
</Styles>
|
</Styles>
|
||||||
@ -2,7 +2,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:segments="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments"
|
xmlns:segments="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="18"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="18"
|
||||||
@ -49,7 +48,7 @@
|
|||||||
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
PointerPressed="KeyframeDragAnchor_OnPointerPressed"
|
||||||
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
PointerMoved="KeyframeDragAnchor_OnPointerMoved"
|
||||||
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
PointerReleased="KeyframeDragAnchor_OnPointerReleased"
|
||||||
ToolTip.Tip="{CompiledBinding EndTimestamp}"/>
|
ToolTip.Tip="{CompiledBinding EndTimestamp}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,10 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
||||||
|
|
||||||
|
public class StartSegmentView : ReactiveUserControl<StartSegmentViewModel>
|
||||||
{
|
{
|
||||||
public partial class StartSegmentView : ReactiveUserControl<StartSegmentViewModel>
|
|
||||||
{
|
|
||||||
private readonly Rectangle _keyframeDragAnchor;
|
private readonly Rectangle _keyframeDragAnchor;
|
||||||
private double _dragOffset;
|
private double _dragOffset;
|
||||||
|
|
||||||
@ -46,5 +46,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments
|
|||||||
e.Pointer.Capture(null);
|
e.Pointer.Capture(null);
|
||||||
ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset);
|
ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,12 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
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 Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using Castle.DynamicProxy.Generators;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
||||||
@ -14,13 +11,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
|||||||
public class StartSegmentViewModel : TimelineSegmentViewModel
|
public class StartSegmentViewModel : TimelineSegmentViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private RenderProfileElement? _profileElement;
|
private readonly ObservableAsPropertyHelper<double> _width;
|
||||||
private int _pixelsPerSecond;
|
|
||||||
private TimeSpan _time;
|
|
||||||
private ObservableAsPropertyHelper<double>? _end;
|
private ObservableAsPropertyHelper<double>? _end;
|
||||||
private ObservableAsPropertyHelper<string?>? _endTimestamp;
|
private ObservableAsPropertyHelper<string?>? _endTimestamp;
|
||||||
private readonly ObservableAsPropertyHelper<double> _width;
|
|
||||||
private TimeSpan _initialLength;
|
private TimeSpan _initialLength;
|
||||||
|
private int _pixelsPerSecond;
|
||||||
|
private RenderProfileElement? _profileElement;
|
||||||
|
private TimeSpan _time;
|
||||||
|
|
||||||
public StartSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
|
public StartSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
|
||||||
{
|
{
|
||||||
@ -52,6 +49,7 @@ public class StartSegmentViewModel : TimelineSegmentViewModel
|
|||||||
public override double StartX => 0;
|
public override double StartX => 0;
|
||||||
public override TimeSpan End => _profileElement?.Timeline.StartSegmentEndPosition ?? TimeSpan.Zero;
|
public override TimeSpan End => _profileElement?.Timeline.StartSegmentEndPosition ?? TimeSpan.Zero;
|
||||||
public override double EndX => _end?.Value ?? 0;
|
public override double EndX => _end?.Value ?? 0;
|
||||||
|
|
||||||
public override TimeSpan Length
|
public override TimeSpan Length
|
||||||
{
|
{
|
||||||
get => _profileElement?.Timeline.StartSegmentLength ?? TimeSpan.Zero;
|
get => _profileElement?.Timeline.StartSegmentLength ?? TimeSpan.Zero;
|
||||||
|
|||||||
@ -15,14 +15,14 @@ public abstract class TimelineSegmentViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private static readonly TimeSpan NewSegmentLength = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan NewSegmentLength = TimeSpan.FromSeconds(2);
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private RenderProfileElement? _profileElement;
|
private TimeSpan _initialLength;
|
||||||
|
private readonly Dictionary<ILayerPropertyKeyframe, TimeSpan> _originalKeyframePositions = new();
|
||||||
private int _pixelsPerSecond;
|
private int _pixelsPerSecond;
|
||||||
private Dictionary<ILayerPropertyKeyframe, TimeSpan> _originalKeyframePositions = new();
|
private RenderProfileElement? _profileElement;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _showAddEnd;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _showAddMain;
|
||||||
|
|
||||||
private ObservableAsPropertyHelper<bool>? _showAddStart;
|
private ObservableAsPropertyHelper<bool>? _showAddStart;
|
||||||
private ObservableAsPropertyHelper<bool>? _showAddMain;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _showAddEnd;
|
|
||||||
private TimeSpan _initialLength;
|
|
||||||
|
|
||||||
protected TimelineSegmentViewModel(IProfileEditorService profileEditorService)
|
protected TimelineSegmentViewModel(IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
@ -136,8 +136,10 @@ public abstract class TimelineSegmentViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
// Delete keyframes in the segment
|
// Delete keyframes in the segment
|
||||||
foreach (ILayerPropertyKeyframe layerPropertyKeyframe in keyframes)
|
foreach (ILayerPropertyKeyframe layerPropertyKeyframe in keyframes)
|
||||||
|
{
|
||||||
if (layerPropertyKeyframe.Position > Start && layerPropertyKeyframe.Position <= End)
|
if (layerPropertyKeyframe.Position > Start && layerPropertyKeyframe.Position <= End)
|
||||||
_profileEditorService.ExecuteCommand(new DeleteKeyframe(layerPropertyKeyframe));
|
_profileEditorService.ExecuteCommand(new DeleteKeyframe(layerPropertyKeyframe));
|
||||||
|
}
|
||||||
|
|
||||||
// Move keyframes after the segment forwards
|
// Move keyframes after the segment forwards
|
||||||
ShiftKeyframes(keyframes.Where(s => s.Position > End), new TimeSpan(Length.Ticks * -1));
|
ShiftKeyframes(keyframes.Where(s => s.Position > End), new TimeSpan(Length.Ticks * -1));
|
||||||
|
|||||||
@ -9,12 +9,10 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.TimelineView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.TimelineView"
|
||||||
x:DataType="timeline:TimelineViewModel">
|
x:DataType="timeline:TimelineViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<x:Double x:Key="RailsHeight">28</x:Double>
|
|
||||||
<x:Double x:Key="RailsBorderHeight">29</x:Double>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Background="Transparent" PointerReleased="InputElement_OnPointerReleased" Focusable="True" MinWidth="{Binding MinWidth}">
|
<Grid Background="Transparent" PointerReleased="InputElement_OnPointerReleased" Focusable="True" MinWidth="{Binding MinWidth}">
|
||||||
<Grid.KeyBindings>
|
<Grid.KeyBindings>
|
||||||
<KeyBinding Command="{Binding DeleteKeyframes}" Gesture="Delete"/>
|
<KeyBinding Command="{Binding DeleteKeyframes}" Gesture="Delete" />
|
||||||
</Grid.KeyBindings>
|
</Grid.KeyBindings>
|
||||||
<ItemsControl Items="{CompiledBinding PropertyGroupViewModels}">
|
<ItemsControl Items="{CompiledBinding PropertyGroupViewModels}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
@ -23,7 +21,7 @@
|
|||||||
</TreeDataTemplate>
|
</TreeDataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
<shared:SelectionRectangle Name="SelectionRectangle" InputElement="{CompiledBinding $parent}" SelectionFinished="SelectionRectangle_OnSelectionFinished"></shared:SelectionRectangle>
|
<shared:SelectionRectangle Name="SelectionRectangle" InputElement="{CompiledBinding $parent}" SelectionFinished="SelectionRectangle_OnSelectionFinished" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,12 +3,10 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.UI.Ninject.Factories;
|
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
@ -18,9 +16,9 @@ public class TimelineViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private ObservableAsPropertyHelper<double>? _caretPosition;
|
private ObservableAsPropertyHelper<double>? _caretPosition;
|
||||||
private ObservableAsPropertyHelper<int>? _pixelsPerSecond;
|
|
||||||
private List<ITimelineKeyframeViewModel>? _moveKeyframes;
|
|
||||||
private ObservableAsPropertyHelper<double> _minWidth;
|
private ObservableAsPropertyHelper<double> _minWidth;
|
||||||
|
private List<ITimelineKeyframeViewModel>? _moveKeyframes;
|
||||||
|
private ObservableAsPropertyHelper<int>? _pixelsPerSecond;
|
||||||
|
|
||||||
public TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels,
|
public TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels,
|
||||||
StartSegmentViewModel startSegmentViewModel,
|
StartSegmentViewModel startSegmentViewModel,
|
||||||
@ -141,8 +139,10 @@ public class TimelineViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public void DuplicateKeyframes(ITimelineKeyframeViewModel? source = null)
|
public void DuplicateKeyframes(ITimelineKeyframeViewModel? source = null)
|
||||||
{
|
{
|
||||||
if (source is { IsSelected: false })
|
if (source is {IsSelected: false})
|
||||||
|
{
|
||||||
source.Delete();
|
source.Delete();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
||||||
@ -154,8 +154,10 @@ public class TimelineViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public void CopyKeyframes(ITimelineKeyframeViewModel? source = null)
|
public void CopyKeyframes(ITimelineKeyframeViewModel? source = null)
|
||||||
{
|
{
|
||||||
if (source is { IsSelected: false })
|
if (source is {IsSelected: false})
|
||||||
|
{
|
||||||
source.Copy();
|
source.Copy();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
||||||
@ -167,8 +169,10 @@ public class TimelineViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public void PasteKeyframes(ITimelineKeyframeViewModel? source = null)
|
public void PasteKeyframes(ITimelineKeyframeViewModel? source = null)
|
||||||
{
|
{
|
||||||
if (source is { IsSelected: false })
|
if (source is {IsSelected: false})
|
||||||
|
{
|
||||||
source.Paste();
|
source.Paste();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
||||||
@ -181,7 +185,9 @@ public class TimelineViewModel : ActivatableViewModelBase
|
|||||||
public void DeleteKeyframes(ITimelineKeyframeViewModel? source = null)
|
public void DeleteKeyframes(ITimelineKeyframeViewModel? source = null)
|
||||||
{
|
{
|
||||||
if (source is {IsSelected: false})
|
if (source is {IsSelected: false})
|
||||||
|
{
|
||||||
source.Delete();
|
source.Delete();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
List<ITimelineKeyframeViewModel> keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList();
|
||||||
|
|||||||
@ -10,6 +10,6 @@
|
|||||||
<StackPanel.KeyBindings>
|
<StackPanel.KeyBindings>
|
||||||
<KeyBinding Gesture="Enter" Command="{CompiledBinding Confirm}" />
|
<KeyBinding Gesture="Enter" Command="{CompiledBinding Confirm}" />
|
||||||
</StackPanel.KeyBindings>
|
</StackPanel.KeyBindings>
|
||||||
<TextBox Name="NameTextBox" Text="{CompiledBinding LayerEffectName}" Watermark="Layer effect name"/>
|
<TextBox Name="NameTextBox" Text="{CompiledBinding LayerEffectName}" Watermark="Layer effect name" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -7,12 +7,12 @@ using FluentAvalonia.UI.Controls;
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Validation.Extensions;
|
using ReactiveUI.Validation.Extensions;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs;
|
||||||
|
|
||||||
|
public class LayerEffectRenameViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
public class LayerEffectRenameViewModel : ContentDialogViewModelBase
|
|
||||||
{
|
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
|
||||||
private readonly BaseLayerEffect _layerEffect;
|
private readonly BaseLayerEffect _layerEffect;
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private string? _layerEffectName;
|
private string? _layerEffectName;
|
||||||
|
|
||||||
public LayerEffectRenameViewModel(IProfileEditorService profileEditorService, BaseLayerEffect layerEffect)
|
public LayerEffectRenameViewModel(IProfileEditorService profileEditorService, BaseLayerEffect layerEffect)
|
||||||
@ -28,7 +28,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs
|
|||||||
public string? LayerEffectName
|
public string? LayerEffectName
|
||||||
{
|
{
|
||||||
get => _layerEffectName;
|
get => _layerEffectName;
|
||||||
set => this.RaiseAndSetIfChanged(ref _layerEffectName, value);
|
set => RaiseAndSetIfChanged(ref _layerEffectName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Confirm { get; }
|
public ReactiveCommand<Unit, Unit> Confirm { get; }
|
||||||
@ -41,5 +41,4 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs
|
|||||||
_profileEditorService.ExecuteCommand(new RenameLayerEffect(_layerEffect, LayerEffectName));
|
_profileEditorService.ExecuteCommand(new RenameLayerEffect(_layerEffect, LayerEffectName));
|
||||||
ContentDialog?.Hide(ContentDialogResult.Primary);
|
ContentDialog?.Hide(ContentDialogResult.Primary);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Reactive;
|
using Artemis.Core;
|
||||||
using Artemis.Core;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree;
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree;
|
||||||
|
|||||||
@ -63,6 +63,19 @@ public class TreeGroupViewModel : ActivatableViewModelBase
|
|||||||
public ReactiveCommand<Unit, Unit> RenameEffect { get; }
|
public ReactiveCommand<Unit, Unit> RenameEffect { get; }
|
||||||
public ReactiveCommand<Unit, Unit> DeleteEffect { get; }
|
public ReactiveCommand<Unit, Unit> DeleteEffect { get; }
|
||||||
|
|
||||||
|
public double GetDepth()
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
LayerPropertyGroup? current = LayerPropertyGroup.Parent;
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
current = current.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ExecuteOpenBrushSettings()
|
private async Task ExecuteOpenBrushSettings()
|
||||||
{
|
{
|
||||||
if (LayerBrush?.ConfigurationDialog is not LayerBrushConfigurationDialog configurationViewModel)
|
if (LayerBrush?.ConfigurationDialog is not LayerBrushConfigurationDialog configurationViewModel)
|
||||||
@ -145,19 +158,6 @@ public class TreeGroupViewModel : ActivatableViewModelBase
|
|||||||
_profileEditorService.ExecuteCommand(new RemoveLayerEffect(LayerEffect));
|
_profileEditorService.ExecuteCommand(new RemoveLayerEffect(LayerEffect));
|
||||||
}
|
}
|
||||||
|
|
||||||
public double GetDepth()
|
|
||||||
{
|
|
||||||
int depth = 0;
|
|
||||||
LayerPropertyGroup? current = LayerPropertyGroup.Parent;
|
|
||||||
while (current != null)
|
|
||||||
{
|
|
||||||
depth++;
|
|
||||||
current = current.Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseViewModels()
|
private void CloseViewModels()
|
||||||
{
|
{
|
||||||
_effectConfigurationWindowViewModel?.Close(null);
|
_effectConfigurationWindowViewModel?.Close(null);
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
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:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:sharedConverters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
|
||||||
xmlns:tree="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Tree"
|
xmlns:tree="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Tree"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.TreePropertyView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.TreePropertyView"
|
||||||
@ -39,7 +38,7 @@
|
|||||||
|
|
||||||
<ContentControl Grid.Column="2"
|
<ContentControl Grid.Column="2"
|
||||||
Margin="5 0"
|
Margin="5 0"
|
||||||
Content="{Binding PropertyInputViewModel}"/>
|
Content="{Binding PropertyInputViewModel}" />
|
||||||
|
|
||||||
<Button Grid.Column="3"
|
<Button Grid.Column="3"
|
||||||
Margin="0 0 2 0"
|
Margin="0 0 2 0"
|
||||||
|
|||||||
@ -15,9 +15,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree;
|
|||||||
internal class TreePropertyViewModel<T> : ActivatableViewModelBase, ITreePropertyViewModel
|
internal class TreePropertyViewModel<T> : ActivatableViewModelBase, ITreePropertyViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private TimeSpan _time;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _isCurrentlySelected;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _dataBindingEnabled;
|
private ObservableAsPropertyHelper<bool>? _dataBindingEnabled;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _isCurrentlySelected;
|
||||||
|
private TimeSpan _time;
|
||||||
|
|
||||||
public TreePropertyViewModel(LayerProperty<T> layerProperty, PropertyViewModel propertyViewModel, IProfileEditorService profileEditorService, IPropertyInputService propertyInputService)
|
public TreePropertyViewModel(LayerProperty<T> layerProperty, PropertyViewModel propertyViewModel, IProfileEditorService profileEditorService, IPropertyInputService propertyInputService)
|
||||||
{
|
{
|
||||||
@ -40,7 +40,6 @@ internal class TreePropertyViewModel<T> : ActivatableViewModelBase, ITreePropert
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCurrentlySelected => _isCurrentlySelected?.Value ?? false;
|
public bool IsCurrentlySelected => _isCurrentlySelected?.Value ?? false;
|
||||||
public bool DataBindingEnabled => _dataBindingEnabled?.Value ?? false;
|
|
||||||
public LayerProperty<T> LayerProperty { get; }
|
public LayerProperty<T> LayerProperty { get; }
|
||||||
public PropertyViewModel PropertyViewModel { get; }
|
public PropertyViewModel PropertyViewModel { get; }
|
||||||
public PropertyInputViewModel<T>? PropertyInputViewModel { get; }
|
public PropertyInputViewModel<T>? PropertyInputViewModel { get; }
|
||||||
@ -65,6 +64,8 @@ internal class TreePropertyViewModel<T> : ActivatableViewModelBase, ITreePropert
|
|||||||
_profileEditorService.ExecuteCommand(new ResetLayerProperty<T>(LayerProperty));
|
_profileEditorService.ExecuteCommand(new ResetLayerProperty<T>(LayerProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DataBindingEnabled => _dataBindingEnabled?.Value ?? false;
|
||||||
|
|
||||||
public ILayerProperty BaseLayerProperty => LayerProperty;
|
public ILayerProperty BaseLayerProperty => LayerProperty;
|
||||||
|
|
||||||
public double GetDepth()
|
public double GetDepth()
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.LayerBrushes;
|
using Artemis.UI.Shared.LayerBrushes;
|
||||||
using Avalonia.Threading;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.LayerEffects;
|
using Artemis.UI.Shared.LayerEffects;
|
||||||
using Avalonia.Threading;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,13 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.StatusBar.StatusBarView">
|
x:Class="Artemis.UI.Screens.ProfileEditor.StatusBar.StatusBarView">
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="Border.status-message-border">
|
<Style Selector="Border.status-message-border">
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrush}"></Setter>
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrush}" />
|
||||||
<Setter Property="BorderThickness" Value="1 0 0 0"></Setter>
|
<Setter Property="BorderThickness" Value="1 0 0 0" />
|
||||||
<Setter Property="Margin" Value="5 2 0 2"></Setter>
|
<Setter Property="Margin" Value="5 2 0 2" />
|
||||||
<Setter Property="Transitions">
|
<Setter Property="Transitions">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<DoubleTransition Property="Opacity" Duration="0.2"></DoubleTransition>
|
<DoubleTransition Property="Opacity" Duration="0.2" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@ -47,6 +47,6 @@
|
|||||||
Maximum="350"
|
Maximum="350"
|
||||||
Width="319"
|
Width="319"
|
||||||
Value="{Binding PixelsPerSecond}"
|
Value="{Binding PixelsPerSecond}"
|
||||||
HorizontalAlignment="Right"/>
|
HorizontalAlignment="Right" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.StatusBar
|
namespace Artemis.UI.Screens.ProfileEditor.StatusBar;
|
||||||
|
|
||||||
|
public class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||||
{
|
{
|
||||||
public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
|
||||||
{
|
|
||||||
public StatusBarView()
|
public StatusBarView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -14,5 +14,4 @@ namespace Artemis.UI.Screens.ProfileEditor.StatusBar
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -13,7 +13,7 @@
|
|||||||
SelectionFinished="SelectionRectangle_OnSelectionFinished"
|
SelectionFinished="SelectionRectangle_OnSelectionFinished"
|
||||||
ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}">
|
ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}">
|
||||||
<shared:SelectionRectangle.Background>
|
<shared:SelectionRectangle.Background>
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2" />
|
||||||
</shared:SelectionRectangle.Background>
|
</shared:SelectionRectangle.Background>
|
||||||
</shared:SelectionRectangle>
|
</shared:SelectionRectangle>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -15,9 +15,9 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Tools;
|
|||||||
|
|
||||||
public class SelectionAddToolViewModel : ToolViewModel
|
public class SelectionAddToolViewModel : ToolViewModel
|
||||||
{
|
{
|
||||||
|
private readonly ObservableAsPropertyHelper<bool>? _isEnabled;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IRgbService _rgbService;
|
private readonly IRgbService _rgbService;
|
||||||
private readonly ObservableAsPropertyHelper<bool>? _isEnabled;
|
|
||||||
private Layer? _layer;
|
private Layer? _layer;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -49,15 +49,6 @@ public class SelectionAddToolViewModel : ToolViewModel
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToolTip => "Add LEDs to the current layer";
|
public override string ToolTip => "Add LEDs to the current layer";
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
_isEnabled?.Dispose();
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLedsInRectangle(SKRect rect, bool expand, bool inverse)
|
public void AddLedsInRectangle(SKRect rect, bool expand, bool inverse)
|
||||||
{
|
{
|
||||||
if (_layer == null)
|
if (_layer == null)
|
||||||
@ -80,4 +71,13 @@ public class SelectionAddToolViewModel : ToolViewModel
|
|||||||
_profileEditorService.ExecuteCommand(new ChangeLayerLeds(_layer, leds.Distinct().ToList()));
|
_profileEditorService.ExecuteCommand(new ChangeLayerLeds(_layer, leds.Distinct().ToList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
_isEnabled?.Dispose();
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@
|
|||||||
SelectionFinished="SelectionRectangle_OnSelectionFinished"
|
SelectionFinished="SelectionRectangle_OnSelectionFinished"
|
||||||
ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}">
|
ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}">
|
||||||
<shared:SelectionRectangle.Background>
|
<shared:SelectionRectangle.Background>
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2" />
|
||||||
</shared:SelectionRectangle.Background>
|
</shared:SelectionRectangle.Background>
|
||||||
</shared:SelectionRectangle>
|
</shared:SelectionRectangle>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
Canvas.Top="{CompiledBinding ShapeBounds.Top}"
|
Canvas.Top="{CompiledBinding ShapeBounds.Top}"
|
||||||
RenderTransformOrigin="{CompiledBinding RelativeAnchor}">
|
RenderTransformOrigin="{CompiledBinding RelativeAnchor}">
|
||||||
<Border.RenderTransform>
|
<Border.RenderTransform>
|
||||||
<RotateTransform Angle="{CompiledBinding Rotation}"></RotateTransform>
|
<RotateTransform Angle="{CompiledBinding Rotation}" />
|
||||||
</Border.RenderTransform>
|
</Border.RenderTransform>
|
||||||
<Grid Name="HandleGrid">
|
<Grid Name="HandleGrid">
|
||||||
<!-- Render these first so that they are always behind the actual shape -->
|
<!-- Render these first so that they are always behind the actual shape -->
|
||||||
|
|||||||
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared.Extensions;
|
using Artemis.UI.Shared.Extensions;
|
||||||
using Artemis.UI.Shared.Providers;
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
@ -24,6 +23,7 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Tools;
|
|||||||
|
|
||||||
public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||||
{
|
{
|
||||||
|
private readonly Grid _handleGrid;
|
||||||
private readonly List<Control> _handles = new();
|
private readonly List<Control> _handles = new();
|
||||||
private readonly Panel _resizeBottomCenter;
|
private readonly Panel _resizeBottomCenter;
|
||||||
private readonly Panel _resizeBottomLeft;
|
private readonly Panel _resizeBottomLeft;
|
||||||
@ -36,7 +36,6 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
|||||||
|
|
||||||
private SKPoint _dragOffset;
|
private SKPoint _dragOffset;
|
||||||
private ZoomBorder? _zoomBorder;
|
private ZoomBorder? _zoomBorder;
|
||||||
private readonly Grid _handleGrid;
|
|
||||||
|
|
||||||
public TransformToolView()
|
public TransformToolView()
|
||||||
{
|
{
|
||||||
@ -358,8 +357,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
|||||||
float startAngle = CalculateAngleToAnchor(e);
|
float startAngle = CalculateAngleToAnchor(e);
|
||||||
_rotationDragOffset = startAngle - ViewModel.Layer.Transform.Rotation;
|
_rotationDragOffset = startAngle - ViewModel.Layer.Transform.Rotation;
|
||||||
ViewModel.StartRotation();
|
ViewModel.StartRotation();
|
||||||
ToolTip.SetTip((Control)sender, $"{ViewModel.Layer.Transform.Rotation.CurrentValue:F3}°");
|
ToolTip.SetTip((Control) sender, $"{ViewModel.Layer.Transform.Rotation.CurrentValue:F3}°");
|
||||||
ToolTip.SetIsOpen((Control)sender, true);
|
ToolTip.SetIsOpen((Control) sender, true);
|
||||||
|
|
||||||
e.Pointer.Capture((IInputElement?) sender);
|
e.Pointer.Capture((IInputElement?) sender);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
@ -376,7 +375,7 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
|||||||
angle += 360;
|
angle += 360;
|
||||||
|
|
||||||
ViewModel?.UpdateRotation(angle, e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
ViewModel?.UpdateRotation(angle, e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
ToolTip.SetTip((Control)sender, $"{ViewModel.Layer.Transform.Rotation.CurrentValue:F3}°");
|
ToolTip.SetTip((Control) sender, $"{ViewModel.Layer.Transform.Rotation.CurrentValue:F3}°");
|
||||||
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
@ -387,8 +386,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ViewModel?.FinishRotation();
|
ViewModel?.FinishRotation();
|
||||||
ToolTip.SetTip((Control)sender, null);
|
ToolTip.SetTip((Control) sender, null);
|
||||||
ToolTip.SetIsOpen((Control)sender, false);
|
ToolTip.SetIsOpen((Control) sender, false);
|
||||||
|
|
||||||
e.Pointer.Capture(null);
|
e.Pointer.Capture(null);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
|
|||||||
@ -185,8 +185,8 @@ public class TransformToolViewModel : ToolViewModel
|
|||||||
// Get a normalized point
|
// Get a normalized point
|
||||||
SKPoint scaled = Layer.GetNormalizedPoint(position, true);
|
SKPoint scaled = Layer.GetNormalizedPoint(position, true);
|
||||||
// Compensate for the anchor
|
// Compensate for the anchor
|
||||||
scaled.X += ((Layer.Transform.AnchorPoint.CurrentValue.X) * (Layer.Transform.Scale.CurrentValue.Width/100f));
|
scaled.X += Layer.Transform.AnchorPoint.CurrentValue.X * (Layer.Transform.Scale.CurrentValue.Width / 100f);
|
||||||
scaled.Y += ((Layer.Transform.AnchorPoint.CurrentValue.Y) * (Layer.Transform.Scale.CurrentValue.Height/100f));
|
scaled.Y += Layer.Transform.AnchorPoint.CurrentValue.Y * (Layer.Transform.Scale.CurrentValue.Height / 100f);
|
||||||
_movementPreview.Preview(scaled);
|
_movementPreview.Preview(scaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
Background="Transparent">
|
Background="Transparent">
|
||||||
<Grid.Transitions>
|
<Grid.Transitions>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut"/>
|
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</Grid.Transitions>
|
</Grid.Transitions>
|
||||||
|
|
||||||
@ -85,15 +85,15 @@
|
|||||||
</paz:ZoomBorder>
|
</paz:ZoomBorder>
|
||||||
<Border CornerRadius="0 0 8 0" VerticalAlignment="Top" HorizontalAlignment="Left">
|
<Border CornerRadius="0 0 8 0" VerticalAlignment="Top" HorizontalAlignment="Left">
|
||||||
<Border.Background>
|
<Border.Background>
|
||||||
<SolidColorBrush Color="{DynamicResource CardStrokeColorDefaultSolid}" Opacity="0.65"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource CardStrokeColorDefaultSolid}" Opacity="0.65" />
|
||||||
</Border.Background>
|
</Border.Background>
|
||||||
<StackPanel Orientation="Horizontal" Margin="8">
|
<StackPanel Orientation="Horizontal" Margin="8">
|
||||||
<shared:ProfileConfigurationIcon ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}"
|
<shared:ProfileConfigurationIcon ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}"
|
||||||
Foreground="{DynamicResource ToolTipForeground}"
|
Foreground="{DynamicResource ToolTipForeground}"
|
||||||
Width="18"
|
Width="18"
|
||||||
Height="18"
|
Height="18"
|
||||||
Margin="0 0 5 0"></shared:ProfileConfigurationIcon>
|
Margin="0 0 5 0" />
|
||||||
<TextBlock Text="{CompiledBinding ProfileConfiguration.Name}"/>
|
<TextBlock Text="{CompiledBinding ProfileConfiguration.Name}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -5,10 +5,10 @@ using Avalonia.Markup.Xaml;
|
|||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor
|
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor;
|
||||||
|
|
||||||
|
public class VisualEditorView : ReactiveUserControl<VisualEditorViewModel>
|
||||||
{
|
{
|
||||||
public class VisualEditorView : ReactiveUserControl<VisualEditorViewModel>
|
|
||||||
{
|
|
||||||
private readonly ZoomBorder _zoomBorder;
|
private readonly ZoomBorder _zoomBorder;
|
||||||
|
|
||||||
public VisualEditorView()
|
public VisualEditorView()
|
||||||
@ -41,5 +41,4 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor
|
|||||||
{
|
{
|
||||||
UpdateZoomBorderBackground();
|
UpdateZoomBorderBackground();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -13,8 +13,8 @@
|
|||||||
<Setter Property="Transitions">
|
<Setter Property="Transitions">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<DoubleTransition Property="StrokeThickness" Duration="0:0:0.2" Easing="CubicEaseOut"></DoubleTransition>
|
<DoubleTransition Property="StrokeThickness" Duration="0:0:0.2" Easing="CubicEaseOut" />
|
||||||
<BrushTransition Property="Stroke" Duration="0:0:0.2" Easing="CubicEaseOut"></BrushTransition>
|
<BrushTransition Property="Stroke" Duration="0:0:0.2" Easing="CubicEaseOut" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<Setter Property="Transitions">
|
<Setter Property="Transitions">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<DoubleTransition Property="StrokeThickness" Duration="0:0:0.2" Easing="CubicEaseOut"></DoubleTransition>
|
<DoubleTransition Property="StrokeThickness" Duration="0:0:0.2" Easing="CubicEaseOut" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@ -43,8 +43,7 @@
|
|||||||
Classes.layer-visualizer-unbound-selected="{CompiledBinding Selected}"
|
Classes.layer-visualizer-unbound-selected="{CompiledBinding Selected}"
|
||||||
Data="{CompiledBinding ShapeGeometry, Mode=OneWay}"
|
Data="{CompiledBinding ShapeGeometry, Mode=OneWay}"
|
||||||
StrokeThickness="4"
|
StrokeThickness="4"
|
||||||
StrokeJoin="Round">
|
StrokeJoin="Round" />
|
||||||
</Path>
|
|
||||||
<Border Name="LayerVisualizerBounds"
|
<Border Name="LayerVisualizerBounds"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Width="{CompiledBinding LayerBounds.Width, Mode=OneWay}"
|
Width="{CompiledBinding LayerBounds.Width, Mode=OneWay}"
|
||||||
@ -54,8 +53,7 @@
|
|||||||
Classes.layer-visualizer-selected="{CompiledBinding Selected}"
|
Classes.layer-visualizer-selected="{CompiledBinding Selected}"
|
||||||
Data="{CompiledBinding ShapeGeometry, Mode=OneWay}"
|
Data="{CompiledBinding ShapeGeometry, Mode=OneWay}"
|
||||||
StrokeThickness="4"
|
StrokeThickness="4"
|
||||||
StrokeJoin="Round">
|
StrokeJoin="Round" />
|
||||||
</Path>
|
|
||||||
</Border>
|
</Border>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
|||||||
@ -12,11 +12,11 @@ using ReactiveUI;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
||||||
|
|
||||||
public partial class LayerShapeVisualizerView : ReactiveUserControl<LayerShapeVisualizerViewModel>
|
public class LayerShapeVisualizerView : ReactiveUserControl<LayerShapeVisualizerViewModel>
|
||||||
{
|
{
|
||||||
private ZoomBorder? _zoomBorder;
|
|
||||||
private readonly Path _layerVisualizerUnbound;
|
|
||||||
private readonly Path _layerVisualizer;
|
private readonly Path _layerVisualizer;
|
||||||
|
private readonly Path _layerVisualizerUnbound;
|
||||||
|
private ZoomBorder? _zoomBorder;
|
||||||
|
|
||||||
public LayerShapeVisualizerView()
|
public LayerShapeVisualizerView()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,11 +15,11 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
|||||||
|
|
||||||
public class LayerShapeVisualizerViewModel : ActivatableViewModelBase, IVisualizerViewModel
|
public class LayerShapeVisualizerViewModel : ActivatableViewModelBase, IVisualizerViewModel
|
||||||
{
|
{
|
||||||
private ObservableAsPropertyHelper<bool>? _selected;
|
|
||||||
private Rect _layerBounds;
|
private Rect _layerBounds;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _selected;
|
||||||
|
private Geometry? _shapeGeometry;
|
||||||
private double _x;
|
private double _x;
|
||||||
private double _y;
|
private double _y;
|
||||||
private Geometry? _shapeGeometry;
|
|
||||||
|
|
||||||
public LayerShapeVisualizerViewModel(Layer layer, IProfileEditorService profileEditorService)
|
public LayerShapeVisualizerViewModel(Layer layer, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
@ -49,7 +49,6 @@ public class LayerShapeVisualizerViewModel : ActivatableViewModelBase, IVisualiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Layer Layer { get; }
|
public Layer Layer { get; }
|
||||||
public ProfileElement ProfileElement => Layer;
|
|
||||||
public bool Selected => _selected?.Value ?? false;
|
public bool Selected => _selected?.Value ?? false;
|
||||||
|
|
||||||
public Rect LayerBounds
|
public Rect LayerBounds
|
||||||
@ -58,26 +57,12 @@ public class LayerShapeVisualizerViewModel : ActivatableViewModelBase, IVisualiz
|
|||||||
private set => RaiseAndSetIfChanged(ref _layerBounds, value);
|
private set => RaiseAndSetIfChanged(ref _layerBounds, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double X
|
|
||||||
{
|
|
||||||
get => _x;
|
|
||||||
set => RaiseAndSetIfChanged(ref _x, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double Y
|
|
||||||
{
|
|
||||||
get => _y;
|
|
||||||
set => RaiseAndSetIfChanged(ref _y, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Geometry? ShapeGeometry
|
public Geometry? ShapeGeometry
|
||||||
{
|
{
|
||||||
get => _shapeGeometry;
|
get => _shapeGeometry;
|
||||||
set => RaiseAndSetIfChanged(ref _shapeGeometry, value);
|
set => RaiseAndSetIfChanged(ref _shapeGeometry, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order => 2;
|
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
UpdateLayerBounds();
|
UpdateLayerBounds();
|
||||||
@ -103,4 +88,20 @@ public class LayerShapeVisualizerViewModel : ActivatableViewModelBase, IVisualiz
|
|||||||
if (ShapeGeometry != null)
|
if (ShapeGeometry != null)
|
||||||
ShapeGeometry.Transform = new MatrixTransform(Layer.GetTransformMatrix(false, true, true, true, LayerBounds.ToSKRect()).ToMatrix());
|
ShapeGeometry.Transform = new MatrixTransform(Layer.GetTransformMatrix(false, true, true, true, LayerBounds.ToSKRect()).ToMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProfileElement ProfileElement => Layer;
|
||||||
|
|
||||||
|
public double X
|
||||||
|
{
|
||||||
|
get => _x;
|
||||||
|
set => RaiseAndSetIfChanged(ref _x, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Y
|
||||||
|
{
|
||||||
|
get => _y;
|
||||||
|
set => RaiseAndSetIfChanged(ref _y, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order => 2;
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<Setter Property="Transitions">
|
<Setter Property="Transitions">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<DoubleTransition Property="Opacity" Duration="0:0:0.2" Easing="CubicEaseOut"></DoubleTransition>
|
<DoubleTransition Property="Opacity" Duration="0:0:0.2" Easing="CubicEaseOut" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
StrokeDashArray="6,2"
|
StrokeDashArray="6,2"
|
||||||
StrokeJoin="Round">
|
StrokeJoin="Round">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<RectangleGeometry Rect="{CompiledBinding LayerBounds}"></RectangleGeometry>
|
<RectangleGeometry Rect="{CompiledBinding LayerBounds}" />
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -7,14 +7,13 @@ using Avalonia.Controls.Shapes;
|
|||||||
using Avalonia.LogicalTree;
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.VisualTree;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers
|
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
||||||
|
|
||||||
|
public class LayerVisualizerView : ReactiveUserControl<LayerVisualizerViewModel>
|
||||||
{
|
{
|
||||||
public partial class LayerVisualizerView : ReactiveUserControl<LayerVisualizerViewModel>
|
|
||||||
{
|
|
||||||
private ZoomBorder? _zoomBorder;
|
|
||||||
private readonly Path _layerVisualizer;
|
private readonly Path _layerVisualizer;
|
||||||
|
private ZoomBorder? _zoomBorder;
|
||||||
|
|
||||||
public LayerVisualizerView()
|
public LayerVisualizerView()
|
||||||
{
|
{
|
||||||
@ -22,6 +21,11 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers
|
|||||||
_layerVisualizer = this.Get<Path>("LayerVisualizer");
|
_layerVisualizer = this.Get<Path>("LayerVisualizer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
#region Overrides of TemplatedControl
|
#region Overrides of TemplatedControl
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -49,10 +53,4 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -7,14 +7,14 @@ using Artemis.UI.Shared.Services.ProfileEditor;
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SKRect = SkiaSharp.SKRect;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
||||||
|
|
||||||
public class LayerVisualizerViewModel : ActivatableViewModelBase, IVisualizerViewModel
|
public class LayerVisualizerViewModel : ActivatableViewModelBase, IVisualizerViewModel
|
||||||
{
|
{
|
||||||
private ObservableAsPropertyHelper<bool>? _selected;
|
|
||||||
private Rect _layerBounds;
|
private Rect _layerBounds;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _selected;
|
||||||
private double _x;
|
private double _x;
|
||||||
private double _y;
|
private double _y;
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ public class LayerVisualizerViewModel : ActivatableViewModelBase, IVisualizerVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Layer Layer { get; }
|
public Layer Layer { get; }
|
||||||
public ProfileElement ProfileElement => Layer;
|
|
||||||
public bool Selected => _selected?.Value ?? false;
|
public bool Selected => _selected?.Value ?? false;
|
||||||
|
|
||||||
public Rect LayerBounds
|
public Rect LayerBounds
|
||||||
@ -45,6 +44,16 @@ public class LayerVisualizerViewModel : ActivatableViewModelBase, IVisualizerVie
|
|||||||
private set => RaiseAndSetIfChanged(ref _layerBounds, value);
|
private set => RaiseAndSetIfChanged(ref _layerBounds, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
SKRect bounds = Layer.GetLayerBounds();
|
||||||
|
LayerBounds = new Rect(0, 0, bounds.Width, bounds.Height);
|
||||||
|
X = bounds.Left;
|
||||||
|
Y = bounds.Top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileElement ProfileElement => Layer;
|
||||||
|
|
||||||
public double X
|
public double X
|
||||||
{
|
{
|
||||||
get => _x;
|
get => _x;
|
||||||
@ -58,12 +67,4 @@ public class LayerVisualizerViewModel : ActivatableViewModelBase, IVisualizerVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int Order => 1;
|
public int Order => 1;
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
SKRect bounds = Layer.GetLayerBounds();
|
|
||||||
LayerBounds = new Rect(0, 0, bounds.Width, bounds.Height);
|
|
||||||
X = bounds.Left;
|
|
||||||
Y = bounds.Top;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -6,13 +6,13 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileEditorTitleBarView">
|
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileEditorTitleBarView">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
<ContentControl Grid.Row="0" Grid.Column="0" Content="{Binding MenuBarViewModel}"></ContentControl>
|
<ContentControl Grid.Row="0" Grid.Column="0" Content="{Binding MenuBarViewModel}" />
|
||||||
|
|
||||||
<!-- This border enables dragging the window in between the menu and the buttons-->
|
<!-- This border enables dragging the window in between the menu and the buttons-->
|
||||||
<Border Grid.Row="0" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Transparent" IsHitTestVisible="False" />
|
<Border Grid.Row="0" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Transparent" IsHitTestVisible="False" />
|
||||||
|
|
||||||
<Button Grid.Column="2" Classes="title-bar-button" Command="{Binding ShowDebugger}" HorizontalAlignment="Right" VerticalAlignment="Top">
|
<Button Grid.Column="2" Classes="title-bar-button" Command="{Binding ShowDebugger}" HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||||
<avalonia:MaterialIcon Kind="Bug"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Bug" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,12 +1,11 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor
|
namespace Artemis.UI.Screens.ProfileEditor;
|
||||||
|
|
||||||
|
public class ProfileEditorTitleBarView : UserControl
|
||||||
{
|
{
|
||||||
public partial class ProfileEditorTitleBarView : UserControl
|
|
||||||
{
|
|
||||||
public ProfileEditorTitleBarView()
|
public ProfileEditorTitleBarView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -20,5 +19,4 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -2,10 +2,10 @@
|
|||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor
|
namespace Artemis.UI.Screens.ProfileEditor;
|
||||||
|
|
||||||
|
public class ProfileEditorTitleBarViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
public class ProfileEditorTitleBarViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
private readonly IDebugService _debugService;
|
private readonly IDebugService _debugService;
|
||||||
|
|
||||||
public ProfileEditorTitleBarViewModel(IDebugService debugService, MenuBarViewModel menuBarViewModel)
|
public ProfileEditorTitleBarViewModel(IDebugService debugService, MenuBarViewModel menuBarViewModel)
|
||||||
@ -20,5 +20,4 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
{
|
{
|
||||||
_debugService.ShowDebugger();
|
_debugService.ShowDebugger();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.ProfileEditor"
|
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.ProfileEditor"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared.Services.ProfileEditor;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared.Services.ProfileEditor;assembly=Artemis.UI.Shared"
|
||||||
@ -11,7 +10,7 @@
|
|||||||
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileEditorView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileEditorView"
|
||||||
x:DataType="profileEditor:ProfileEditorViewModel">
|
x:DataType="profileEditor:ProfileEditorViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="Border.suspended-editing">
|
<Style Selector="Border.suspended-editing">
|
||||||
@ -22,10 +21,10 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<UserControl.KeyBindings>
|
<UserControl.KeyBindings>
|
||||||
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z" />
|
||||||
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y" />
|
||||||
<KeyBinding Command="{CompiledBinding ToggleSuspend}" Gesture="F5"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding ToggleSuspend}" Gesture="F5" />
|
||||||
<KeyBinding Command="{CompiledBinding ToggleAutoSuspend}" Gesture="Shift+F5"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding ToggleAutoSuspend}" Gesture="Shift+F5" />
|
||||||
</UserControl.KeyBindings>
|
</UserControl.KeyBindings>
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="GridSplitter.editor-grid-splitter-vertical">
|
<Style Selector="GridSplitter.editor-grid-splitter-vertical">
|
||||||
@ -46,7 +45,7 @@
|
|||||||
<Setter Property="Height" Value="18" />
|
<Setter Property="Height" Value="18" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Window:windows Grid.editor-grid">
|
<Style Selector="Window:windows Grid.editor-grid">
|
||||||
<Setter Property="Margin" Value="0 0 4 4"></Setter>
|
<Setter Property="Margin" Value="0 0 4 4" />
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid Classes="editor-grid">
|
<Grid Classes="editor-grid">
|
||||||
@ -127,7 +126,7 @@
|
|||||||
|
|
||||||
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
||||||
<Panel>
|
<Panel>
|
||||||
<ContentControl Content="{CompiledBinding DisplayConditionScriptViewModel}"></ContentControl>
|
<ContentControl Content="{CompiledBinding DisplayConditionScriptViewModel}" />
|
||||||
<Border Classes="suspended-editing" />
|
<Border Classes="suspended-editing" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@ -2,10 +2,10 @@ using Avalonia.Interactivity;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor
|
namespace Artemis.UI.Screens.ProfileEditor;
|
||||||
|
|
||||||
|
public class ProfileEditorView : ReactiveUserControl<ProfileEditorViewModel>
|
||||||
{
|
{
|
||||||
public class ProfileEditorView : ReactiveUserControl<ProfileEditorViewModel>
|
|
||||||
{
|
|
||||||
public ProfileEditorView()
|
public ProfileEditorView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -18,7 +18,5 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
|
|
||||||
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,5 +97,6 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
|
|
||||||
private void ExecuteToggleAutoSuspend()
|
private void ExecuteToggleAutoSuspend()
|
||||||
{
|
{
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,18 +151,9 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?"))
|
if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_profileConfiguration.IsBeingEdited)
|
if (_profileConfiguration.IsBeingEdited)
|
||||||
_profileEditorService.ChangeCurrentProfileConfiguration(null);
|
_profileEditorService.ChangeCurrentProfileConfiguration(null);
|
||||||
_profileService.RemoveProfileConfiguration(_profileConfiguration);
|
_profileService.RemoveProfileConfiguration(_profileConfiguration);
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
Close(_profileConfiguration);
|
Close(_profileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
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"
|
||||||
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">
|
||||||
<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" />
|
||||||
@ -26,11 +27,14 @@
|
|||||||
<Style Selector="Border.fadable.suspended">
|
<Style Selector="Border.fadable.suspended">
|
||||||
<Setter Property="Opacity" Value="1" />
|
<Setter Property="Opacity" Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector=".sidebar-listbox > ListBoxItem">
|
||||||
|
<Setter Property="Padding" Value="6 0"/>
|
||||||
|
</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" 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="{Binding ShowItems}"
|
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !IsCollapsed}"
|
||||||
Kind="ChevronUp"
|
Kind="ChevronUp"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="5 0"
|
Margin="5 0"
|
||||||
@ -44,13 +48,14 @@
|
|||||||
</avalonia:MaterialIcon>
|
</avalonia:MaterialIcon>
|
||||||
|
|
||||||
<TextBlock Classes="fadable"
|
<TextBlock Classes="fadable"
|
||||||
Classes.suspended="{Binding IsSuspended}"
|
Classes.suspended="{CompiledBinding IsSuspended}"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Padding="0 5"
|
Padding="0 5"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
FontSize="13"
|
FontSize="13"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{Binding ProfileCategory.Name, FallbackValue='Profile name'}"
|
Text="{CompiledBinding ProfileCategory.Name, FallbackValue='Profile name'}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
PointerPressed="Title_OnPointerPressed"
|
PointerPressed="Title_OnPointerPressed"
|
||||||
Background="Transparent">
|
Background="Transparent">
|
||||||
<TextBlock.Transitions>
|
<TextBlock.Transitions>
|
||||||
@ -61,7 +66,7 @@
|
|||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<Border Classes="fadable"
|
<Border Classes="fadable"
|
||||||
Classes.suspended="{Binding IsSuspended}"
|
Classes.suspended="{CompiledBinding IsSuspended}"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
BorderBrush="White"
|
BorderBrush="White"
|
||||||
BorderThickness="0.5"
|
BorderThickness="0.5"
|
||||||
@ -77,29 +82,34 @@
|
|||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
ToolTip.Tip="Edit category"
|
ToolTip.Tip="Edit category"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Command="{Binding EditCategory}">
|
Command="{CompiledBinding EditCategory}"
|
||||||
|
Margin="0 0 2 0">
|
||||||
<avalonia:MaterialIcon Kind="Cog" />
|
<avalonia:MaterialIcon Kind="Cog" />
|
||||||
</Button>
|
</Button>
|
||||||
<ToggleButton Classes="category-button icon-button icon-button-small"
|
<Button Classes="icon-button icon-button-small"
|
||||||
|
Command="{CompiledBinding ToggleSuspended}"
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
ToolTip.Tip="Suspend category"
|
ToolTip.Tip="Suspend/resume profile"
|
||||||
Margin="5 0"
|
Margin="0 0 2 0">
|
||||||
IsChecked="{Binding IsSuspended}">
|
<Panel>
|
||||||
<avalonia:MaterialIcon Kind="Pause" />
|
<avalonia:MaterialIcon Kind="EyeOff" IsVisible="{CompiledBinding IsSuspended}" />
|
||||||
</ToggleButton>
|
<avalonia:MaterialIcon Kind="Eye" IsVisible="{CompiledBinding !IsSuspended}" />
|
||||||
|
</Panel>
|
||||||
|
</Button>
|
||||||
<Button Classes="category-button icon-button icon-button-small"
|
<Button Classes="category-button icon-button icon-button-small"
|
||||||
Grid.Column="4"
|
Grid.Column="4"
|
||||||
ToolTip.Tip="Add profile"
|
ToolTip.Tip="Add profile"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Command="{Binding AddProfile}">
|
Command="{CompiledBinding AddProfile}"
|
||||||
|
Margin="0 0 2 0">
|
||||||
<avalonia:MaterialIcon Kind="Plus" />
|
<avalonia:MaterialIcon Kind="Plus" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Grid.Row="1">
|
<Border Grid.Row="1">
|
||||||
<ListBox Classes="sidebar-listbox"
|
<ListBox Classes="sidebar-listbox"
|
||||||
Items="{Binding ProfileConfigurations}"
|
Items="{CompiledBinding ProfileConfigurations}"
|
||||||
SelectedItem="{Binding SelectedProfileConfiguration}"
|
SelectedItem="{CompiledBinding SelectedProfileConfiguration}"
|
||||||
MinHeight="10"
|
MinHeight="10"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Disabled">
|
ScrollViewer.VerticalScrollBarVisibility="Disabled">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Avalonia.Input;
|
using System;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
@ -18,8 +19,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
|
|
||||||
private void Title_OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
private void Title_OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel != null)
|
ViewModel?.ToggleCollapsed.Execute().Subscribe();
|
||||||
ViewModel.ShowItems = !ViewModel.ShowItems;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
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.Events;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
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 ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Sidebar
|
namespace Artemis.UI.Screens.Sidebar
|
||||||
@ -21,6 +25,8 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
private readonly ISidebarVmFactory _vmFactory;
|
private readonly ISidebarVmFactory _vmFactory;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration;
|
private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _isCollapsed;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
||||||
|
|
||||||
public SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory, IProfileService profileService, IWindowService windowService,
|
public SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory, IProfileService profileService, IWindowService windowService,
|
||||||
IProfileEditorService profileEditorService, ISidebarVmFactory vmFactory)
|
IProfileEditorService profileEditorService, ISidebarVmFactory vmFactory)
|
||||||
@ -31,24 +37,59 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
_vmFactory = vmFactory;
|
_vmFactory = vmFactory;
|
||||||
|
|
||||||
ProfileCategory = profileCategory;
|
ProfileCategory = profileCategory;
|
||||||
|
SourceCache<ProfileConfiguration, Guid> profileConfigurations = new(t => t.ProfileId);
|
||||||
|
|
||||||
if (ShowItems)
|
// Only show items when not collapsed
|
||||||
CreateProfileViewModels();
|
IObservable<Func<ProfileConfiguration, bool>> profileConfigurationsFilter = this.WhenAnyValue(vm => vm.IsCollapsed).Select(b => new Func<object, bool>(_ => !b));
|
||||||
|
profileConfigurations.Connect()
|
||||||
|
.SortBy(c => c.Order)
|
||||||
|
.Filter(profileConfigurationsFilter)
|
||||||
|
.Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c))
|
||||||
|
.Bind(out ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> profileConfigurationViewModels)
|
||||||
|
.Subscribe();
|
||||||
|
ProfileConfigurations = profileConfigurationViewModels;
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
ToggleCollapsed = ReactiveCommand.Create(ExecuteToggleCollapsed);
|
||||||
|
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended);
|
||||||
|
AddProfile = ReactiveCommand.CreateFromTask(ExecuteAddProfile);
|
||||||
|
EditCategory = ReactiveCommand.CreateFromTask(ExecuteEditCategory);
|
||||||
|
|
||||||
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
profileEditorService.ProfileConfiguration
|
// Update the list of profiles whenever the category fires events
|
||||||
.Subscribe(p => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => ReferenceEquals(c.ProfileConfiguration, p)))
|
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x)
|
||||||
.DisposeWith(disposables);
|
.Subscribe(e => profileConfigurations.AddOrUpdate(e.EventArgs.ProfileConfiguration))
|
||||||
this.WhenAnyValue(vm => vm.SelectedProfileConfiguration)
|
.DisposeWith(d);
|
||||||
.WhereNotNull()
|
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationRemoved += x, x => profileCategory.ProfileConfigurationRemoved -= x)
|
||||||
.Subscribe(s => profileEditorService.ChangeCurrentProfileConfiguration(s.ProfileConfiguration));
|
.Subscribe(e => profileConfigurations.Remove(e.EventArgs.ProfileConfiguration))
|
||||||
|
.DisposeWith(d);
|
||||||
|
|
||||||
|
profileEditorService.ProfileConfiguration.Subscribe(p => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => ReferenceEquals(c.ProfileConfiguration, p)))
|
||||||
|
.DisposeWith(d);
|
||||||
|
|
||||||
|
_isCollapsed = ProfileCategory.WhenAnyValue(vm => vm.IsCollapsed).ToProperty(this, vm => vm.IsCollapsed).DisposeWith(d);
|
||||||
|
_isSuspended = ProfileCategory.WhenAnyValue(vm => vm.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d);
|
||||||
|
|
||||||
|
// Change the current profile configuration when a new one is selected
|
||||||
|
this.WhenAnyValue(vm => vm.SelectedProfileConfiguration).WhereNotNull().Subscribe(s => profileEditorService.ChangeCurrentProfileConfiguration(s.ProfileConfiguration));
|
||||||
|
});
|
||||||
|
|
||||||
|
profileConfigurations.Edit(updater =>
|
||||||
|
{
|
||||||
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
|
updater.AddOrUpdate(profileConfiguration);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> ToggleCollapsed { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> AddProfile { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> EditCategory { get; }
|
||||||
public ProfileCategory ProfileCategory { get; }
|
public ProfileCategory ProfileCategory { get; }
|
||||||
|
public ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> ProfileConfigurations { get; }
|
||||||
|
|
||||||
public ObservableCollection<SidebarProfileConfigurationViewModel> ProfileConfigurations { get; } = new();
|
public bool IsCollapsed => _isCollapsed?.Value ?? false;
|
||||||
|
public bool IsSuspended => _isSuspended?.Value ?? false;
|
||||||
|
|
||||||
public SidebarProfileConfigurationViewModel? SelectedProfileConfiguration
|
public SidebarProfileConfigurationViewModel? SelectedProfileConfiguration
|
||||||
{
|
{
|
||||||
@ -56,34 +97,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
set => RaiseAndSetIfChanged(ref _selectedProfileConfiguration, value);
|
set => RaiseAndSetIfChanged(ref _selectedProfileConfiguration, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowItems
|
private async Task ExecuteEditCategory()
|
||||||
{
|
|
||||||
get => !ProfileCategory.IsCollapsed;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ProfileCategory.IsCollapsed = !value;
|
|
||||||
if (ProfileCategory.IsCollapsed)
|
|
||||||
ProfileConfigurations.Clear();
|
|
||||||
else
|
|
||||||
CreateProfileViewModels();
|
|
||||||
_profileService.SaveProfileCategory(ProfileCategory);
|
|
||||||
|
|
||||||
this.RaisePropertyChanged(nameof(ShowItems));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSuspended
|
|
||||||
{
|
|
||||||
get => ProfileCategory.IsSuspended;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ProfileCategory.IsSuspended = value;
|
|
||||||
this.RaisePropertyChanged(nameof(IsSuspended));
|
|
||||||
_profileService.SaveProfileCategory(ProfileCategory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task EditCategory()
|
|
||||||
{
|
{
|
||||||
await _windowService.CreateContentDialog()
|
await _windowService.CreateContentDialog()
|
||||||
.WithTitle("Edit category")
|
.WithTitle("Edit category")
|
||||||
@ -97,7 +111,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
_sidebarViewModel.UpdateProfileCategories();
|
_sidebarViewModel.UpdateProfileCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddProfile()
|
private async Task ExecuteAddProfile()
|
||||||
{
|
{
|
||||||
ProfileConfiguration? result = await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
|
ProfileConfiguration? result = await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
|
||||||
("profileCategory", ProfileCategory),
|
("profileCategory", ProfileCategory),
|
||||||
@ -106,18 +120,20 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, result);
|
SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, result);
|
||||||
ProfileConfigurations.Insert(0, viewModel);
|
|
||||||
SelectedProfileConfiguration = viewModel;
|
SelectedProfileConfiguration = viewModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateProfileViewModels()
|
private void ExecuteToggleCollapsed()
|
||||||
{
|
{
|
||||||
ProfileConfigurations.Clear();
|
ProfileCategory.IsCollapsed = !ProfileCategory.IsCollapsed;
|
||||||
foreach (ProfileConfiguration profileConfiguration in ProfileCategory.ProfileConfigurations.OrderBy(p => p.Order))
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
ProfileConfigurations.Add(_vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, profileConfiguration));
|
}
|
||||||
|
|
||||||
SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited);
|
private void ExecuteToggleSuspended()
|
||||||
|
{
|
||||||
|
ProfileCategory.IsSuspended = !ProfileCategory.IsSuspended;
|
||||||
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,15 +106,18 @@
|
|||||||
Classes="icon-button icon-button-small"
|
Classes="icon-button icon-button-small"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
ToolTip.Tip="View properties"
|
ToolTip.Tip="View properties"
|
||||||
HorizontalAlignment="Right">
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 2 0">
|
||||||
<avalonia:MaterialIcon Kind="Cog" />
|
<avalonia:MaterialIcon Kind="Cog" />
|
||||||
</Button>
|
</Button>
|
||||||
<ToggleButton Classes="icon-button icon-button-small"
|
<Button Classes="icon-button icon-button-small"
|
||||||
|
Command="{CompiledBinding ToggleSuspended}"
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
ToolTip.Tip="Suspend profile"
|
ToolTip.Tip="Suspend/resume profile">
|
||||||
Margin="2 0 0 0"
|
<Panel>
|
||||||
IsChecked="{CompiledBinding IsSuspended}">
|
<avalonia:MaterialIcon Kind="EyeOff" IsVisible="{CompiledBinding IsSuspended}" />
|
||||||
<avalonia:MaterialIcon Kind="Pause" />
|
<avalonia:MaterialIcon Kind="Eye" IsVisible="{CompiledBinding !IsSuspended}" />
|
||||||
</ToggleButton>
|
</Panel>
|
||||||
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -26,31 +26,22 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
|
|
||||||
ProfileConfiguration = profileConfiguration;
|
ProfileConfiguration = profileConfiguration;
|
||||||
EditProfile = ReactiveCommand.CreateFromTask(ExecuteEditProfile);
|
EditProfile = ReactiveCommand.CreateFromTask(ExecuteEditProfile);
|
||||||
|
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
_isSuspended = ProfileConfiguration.WhenAnyValue(c => c.IsSuspended)
|
_isSuspended = ProfileConfiguration.WhenAnyValue(c => c.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d);
|
||||||
.ToProperty(this, vm => vm.IsSuspended)
|
|
||||||
.DisposeWith(d);
|
|
||||||
});
|
});
|
||||||
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> EditProfile { get; }
|
public ReactiveCommand<Unit, Unit> EditProfile { get; }
|
||||||
|
public ReactiveCommand<Unit,Unit> ToggleSuspended { get; }
|
||||||
|
|
||||||
public bool IsProfileActive => ProfileConfiguration.Profile != null;
|
public bool IsSuspended => _isSuspended?.Value ?? false;
|
||||||
|
|
||||||
public bool IsSuspended
|
private async Task ExecuteEditProfile()
|
||||||
{
|
|
||||||
get => _isSuspended?.Value ?? false;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ProfileConfiguration.IsSuspended = value;
|
|
||||||
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ExecuteEditProfile()
|
|
||||||
{
|
{
|
||||||
ProfileConfiguration? edited = await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
|
ProfileConfiguration? edited = await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
|
||||||
("profileCategory", ProfileConfiguration.Category),
|
("profileCategory", ProfileConfiguration.Category),
|
||||||
@ -60,5 +51,11 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
if (edited != null)
|
if (edited != null)
|
||||||
_sidebarViewModel.UpdateProfileCategories();
|
_sidebarViewModel.UpdateProfileCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleSuspended()
|
||||||
|
{
|
||||||
|
ProfileConfiguration.IsSuspended = !ProfileConfiguration.IsSuspended;
|
||||||
|
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user