1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Profile editor - WIPeroony

This commit is contained in:
Robert 2021-12-26 19:42:37 +01:00
parent 16b6bb47b4
commit bfbe29be63
36 changed files with 520 additions and 64 deletions

View File

@ -756,6 +756,11 @@
Closes the window hosting the view model
</summary>
</member>
<member name="M:Artemis.UI.Shared.PluginConfigurationViewModel.OnCloseRequested">
<summary>
Called when the the window hosting the view model should close
</summary>
</member>
<member name="E:Artemis.UI.Shared.PluginConfigurationViewModel.CloseRequested">
<summary>
Occurs when the the window hosting the view model should close

View File

@ -219,8 +219,8 @@
},
"FluentAvaloniaUI": {
"type": "Transitive",
"resolved": "1.1.6",
"contentHash": "EJukyiTmEVhaYlHdntFMyQKI4+u772rSClKYQqJRfkTb1NoJXLqiIVqMjx8ZQ0pxnfih+6CZ7+x82lfrGHIPUw==",
"resolved": "1.1.7",
"contentHash": "Hco3+M09A7rDknaYu5CcyGhUOqGj5mebrFzjZVGjW5YBYiMiV+x0vl2Fn6oIfXxhKgg1i70tTwQCtW/1GWFJeA==",
"dependencies": {
"Avalonia": "0.10.10",
"Avalonia.Desktop": "0.10.10",
@ -689,16 +689,16 @@
},
"Splat": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "7iW45RA7AbSlQPCgdokmysva5PGd6iBUhuNkC0XD73LF9dxfTkKeo3wZkohU7nvspDhJ7PJsYHvDtxIt5bMQ8Q=="
"resolved": "14.1.1",
"contentHash": "bKQtKu57w+iJ1T+WDyDdNq+LBNVdmNu2i0vGNyUdtmg4TEIEFiX2GfPusNEAW2QOfxyDE7i4+xTxbOKZr/4jhg=="
},
"Splat.Ninject": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "rTF0HSa6p8nxrXj2hwVgkutcTDJUXY34sY+zYK4ky65b7a0ROL8kdiYyxVVLE4Lq31N5Rcd4bBbqlPkgwZguww==",
"resolved": "14.1.1",
"contentHash": "lmhjY5yRKL6SgkwY0kEtnHI8JERYhRwFiOk+NgvOUtGYzVm/RRm1OrgrN+kPKzmuvsUrodx6FYTHrSkHL2I8Yg==",
"dependencies": {
"Ninject": "3.3.4",
"Splat": "13.1.63"
"Splat": "14.1.1"
}
},
"Svg.Custom": {
@ -1692,12 +1692,12 @@
"Avalonia.Diagnostics": "0.10.10",
"Avalonia.ReactiveUI": "0.10.10",
"Avalonia.Svg.Skia": "0.10.10",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Flurl.Http": "3.2.0",
"Live.Avalonia": "1.3.1",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1",
"Splat.Ninject": "13.1.63"
"Splat.Ninject": "14.1.1"
}
},
"artemis.ui.shared": {
@ -1710,7 +1710,7 @@
"Avalonia.Xaml.Behaviors": "0.10.10.4",
"Avalonia.Xaml.Interactions": "0.10.10.4",
"Avalonia.Xaml.Interactivity": "0.10.10.4",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1"
}

View File

@ -210,8 +210,8 @@
},
"FluentAvaloniaUI": {
"type": "Transitive",
"resolved": "1.1.6",
"contentHash": "EJukyiTmEVhaYlHdntFMyQKI4+u772rSClKYQqJRfkTb1NoJXLqiIVqMjx8ZQ0pxnfih+6CZ7+x82lfrGHIPUw==",
"resolved": "1.1.7",
"contentHash": "Hco3+M09A7rDknaYu5CcyGhUOqGj5mebrFzjZVGjW5YBYiMiV+x0vl2Fn6oIfXxhKgg1i70tTwQCtW/1GWFJeA==",
"dependencies": {
"Avalonia": "0.10.10",
"Avalonia.Desktop": "0.10.10",
@ -688,16 +688,16 @@
},
"Splat": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "7iW45RA7AbSlQPCgdokmysva5PGd6iBUhuNkC0XD73LF9dxfTkKeo3wZkohU7nvspDhJ7PJsYHvDtxIt5bMQ8Q=="
"resolved": "14.1.1",
"contentHash": "bKQtKu57w+iJ1T+WDyDdNq+LBNVdmNu2i0vGNyUdtmg4TEIEFiX2GfPusNEAW2QOfxyDE7i4+xTxbOKZr/4jhg=="
},
"Splat.Ninject": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "rTF0HSa6p8nxrXj2hwVgkutcTDJUXY34sY+zYK4ky65b7a0ROL8kdiYyxVVLE4Lq31N5Rcd4bBbqlPkgwZguww==",
"resolved": "14.1.1",
"contentHash": "lmhjY5yRKL6SgkwY0kEtnHI8JERYhRwFiOk+NgvOUtGYzVm/RRm1OrgrN+kPKzmuvsUrodx6FYTHrSkHL2I8Yg==",
"dependencies": {
"Ninject": "3.3.4",
"Splat": "13.1.63"
"Splat": "14.1.1"
}
},
"Svg.Custom": {
@ -1691,12 +1691,12 @@
"Avalonia.Diagnostics": "0.10.10",
"Avalonia.ReactiveUI": "0.10.10",
"Avalonia.Svg.Skia": "0.10.10",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Flurl.Http": "3.2.0",
"Live.Avalonia": "1.3.1",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1",
"Splat.Ninject": "13.1.63"
"Splat.Ninject": "14.1.1"
}
},
"artemis.ui.shared": {
@ -1709,7 +1709,7 @@
"Avalonia.Xaml.Behaviors": "0.10.10.4",
"Avalonia.Xaml.Interactions": "0.10.10.4",
"Avalonia.Xaml.Interactivity": "0.10.10.4",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1"
}

View File

@ -22,7 +22,7 @@
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.10.4" />
<PackageReference Include="Avalonia.Xaml.Interactions" Version="0.10.10.4" />
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="0.10.10.4" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.6" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.7" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1" />
</ItemGroup>

View File

@ -27,4 +27,16 @@
<StyleInclude Source="/Styles/TextBlock.axaml" />
<StyleInclude Source="/Styles/Sidebar.axaml" />
<StyleInclude Source="/Styles/InfoBar.axaml" />
<StyleInclude Source="/Styles/TreeView.axaml" />
<Style Selector="Window:windows:windows10 /template/ Border#RootBorder">
<!-- This will show if custom accent color setting is used in Settings page-->
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColor}" />
<Setter Property="BorderThickness" Value="0 1 0 0" />
</Style>
<Style Selector="Window[IsActive=False]:windows:windows10 /template/ Border#RootBorder">
<Setter Property="BorderBrush" Value="#3d3d3d" />
<Setter Property="BorderThickness" Value="0 1 0 0" />
</Style>
</Styles>

View File

@ -0,0 +1,99 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="30" MinWidth="350" Height="600">
<TreeView Classes="no-right-margin">
<TreeViewItem>
<TreeViewItem.Header>
<Border BorderThickness="2" BorderBrush="Red">
<TextBlock>Test</TextBlock>
</Border>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Header="Item 2" IsExpanded="True">
<TreeViewItem>
<TreeViewItem.Header>
<Border BorderThickness="2" BorderBrush="Red">
<TextBlock>Test</TextBlock>
</Border>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Header="SubItem2" />
<TreeViewItem Header="SubItem3" IsExpanded="True">
<TreeViewItem>
<TreeViewItem.Header>
<Border BorderThickness="2" BorderBrush="Red">
<TextBlock>Test</TextBlock>
</Border>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Header="SubItem Item2" />
<TreeViewItem Header="SubItem Item3" />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="Item3" />
<TreeViewItem Header="Item4" />
</TreeView>
</Border>
</Design.PreviewWith>
<Style Selector="TreeView.no-right-margin TreeViewItem">
<Setter Property="Template">
<ControlTemplate>
<StackPanel>
<Border Name="PART_LayoutRoot"
Classes="TreeViewItemLayoutRoot"
Focusable="True"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinHeight="{TemplateBinding MinHeight}"
CornerRadius="{TemplateBinding CornerRadius}"
TemplatedControl.IsTemplateFocusTarget="True"
Margin="2 2 0 2">
<Panel>
<Border Name="SelectionIndicator"
Width="3"
Height="16"
HorizontalAlignment="Left"
VerticalAlignment="Center"
CornerRadius="2" />
<Grid Name="PART_Header"
ColumnDefinitions="Auto, *"
Margin="{TemplateBinding Level, Mode=OneWay, Converter={StaticResource TreeViewItemLeftMarginConverter}}">
<Panel Name="PART_ExpandCollapseChevronContainer"
Margin="{StaticResource TreeViewItemExpandCollapseChevronMargin}">
<ToggleButton Name="PART_ExpandCollapseChevron"
Classes="ExpandCollapseChevron"
Focusable="False"
IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}" />
</Panel>
<ContentPresenter Name="PART_HeaderPresenter"
Grid.Column="1"
Focusable="False"
Content="{TemplateBinding Header}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="{TemplateBinding Padding}" />
</Grid>
</Panel>
</Border>
<ItemsPresenter Name="PART_ItemsPresenter"
IsVisible="{TemplateBinding IsExpanded}"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
Margin="2 2 0 2"/>
</StackPanel>
</ControlTemplate>
</Setter>
</Style>
<!-- <Style Selector="TreeView.no-right-margin TreeViewItem /template/ Border#TreeViewItemLayoutRoot"> -->
<!-- <Setter Property="Margin" Value="2 2 0 2"/> -->
<!-- </Style> -->
<!-- <Style Selector="TreeView.no-right-margin TreeViewItem /template/ StackPanel ItemsPresenter#PART_ItemsPresenter"> -->
<!-- <Setter Property="Margin" Value="2 2 0 2"/> -->
<!-- </Style> -->
</Styles>

View File

@ -72,9 +72,9 @@
},
"FluentAvaloniaUI": {
"type": "Direct",
"requested": "[1.1.6, )",
"resolved": "1.1.6",
"contentHash": "EJukyiTmEVhaYlHdntFMyQKI4+u772rSClKYQqJRfkTb1NoJXLqiIVqMjx8ZQ0pxnfih+6CZ7+x82lfrGHIPUw==",
"requested": "[1.1.7, )",
"resolved": "1.1.7",
"contentHash": "Hco3+M09A7rDknaYu5CcyGhUOqGj5mebrFzjZVGjW5YBYiMiV+x0vl2Fn6oIfXxhKgg1i70tTwQCtW/1GWFJeA==",
"dependencies": {
"Avalonia": "0.10.10",
"Avalonia.Desktop": "0.10.10",

View File

@ -226,8 +226,8 @@
},
"FluentAvaloniaUI": {
"type": "Transitive",
"resolved": "1.1.6",
"contentHash": "EJukyiTmEVhaYlHdntFMyQKI4+u772rSClKYQqJRfkTb1NoJXLqiIVqMjx8ZQ0pxnfih+6CZ7+x82lfrGHIPUw==",
"resolved": "1.1.7",
"contentHash": "Hco3+M09A7rDknaYu5CcyGhUOqGj5mebrFzjZVGjW5YBYiMiV+x0vl2Fn6oIfXxhKgg1i70tTwQCtW/1GWFJeA==",
"dependencies": {
"Avalonia": "0.10.10",
"Avalonia.Desktop": "0.10.10",
@ -704,16 +704,16 @@
},
"Splat": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "7iW45RA7AbSlQPCgdokmysva5PGd6iBUhuNkC0XD73LF9dxfTkKeo3wZkohU7nvspDhJ7PJsYHvDtxIt5bMQ8Q=="
"resolved": "14.1.1",
"contentHash": "bKQtKu57w+iJ1T+WDyDdNq+LBNVdmNu2i0vGNyUdtmg4TEIEFiX2GfPusNEAW2QOfxyDE7i4+xTxbOKZr/4jhg=="
},
"Splat.Ninject": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "rTF0HSa6p8nxrXj2hwVgkutcTDJUXY34sY+zYK4ky65b7a0ROL8kdiYyxVVLE4Lq31N5Rcd4bBbqlPkgwZguww==",
"resolved": "14.1.1",
"contentHash": "lmhjY5yRKL6SgkwY0kEtnHI8JERYhRwFiOk+NgvOUtGYzVm/RRm1OrgrN+kPKzmuvsUrodx6FYTHrSkHL2I8Yg==",
"dependencies": {
"Ninject": "3.3.4",
"Splat": "13.1.63"
"Splat": "14.1.1"
}
},
"Svg.Custom": {
@ -1707,12 +1707,12 @@
"Avalonia.Diagnostics": "0.10.10",
"Avalonia.ReactiveUI": "0.10.10",
"Avalonia.Svg.Skia": "0.10.10",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Flurl.Http": "3.2.0",
"Live.Avalonia": "1.3.1",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1",
"Splat.Ninject": "13.1.63"
"Splat.Ninject": "14.1.1"
}
},
"artemis.ui.shared": {
@ -1725,7 +1725,7 @@
"Avalonia.Xaml.Behaviors": "0.10.10.4",
"Avalonia.Xaml.Interactions": "0.10.10.4",
"Avalonia.Xaml.Interactivity": "0.10.10.4",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1"
}

View File

@ -19,12 +19,12 @@
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.10" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.10" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.6" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.7" />
<PackageReference Include="Flurl.Http" Version="3.2.0" />
<PackageReference Include="Live.Avalonia" Version="1.3.1" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1" />
<PackageReference Include="Splat.Ninject" Version="13.1.63" />
<PackageReference Include="Splat.Ninject" Version="14.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Artemis.Core\Artemis.Core.csproj" />
@ -58,4 +58,7 @@
<DependentUpon>ProfileConfigurationEditView.axaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Screens\ProfileEditor\Tools\" />
</ItemGroup>
</Project>

View File

@ -4,6 +4,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Cdevice_005Ctabs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Cplugins_005Cdialogs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Cprofileeditor_005Cpanels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Cprofileeditor_005Ctools/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Csettings_005Ctabs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Csidebar_005Ccontentdialogs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Csidebar_005Cdialogs/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -1,13 +1,22 @@
<Window xmlns="https://github.com/avaloniaui"
<controls:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.MainWindow"
Icon="/Assets/Images/Logo/bow.ico"
Title="Artemis 2.0">
<controls:CoreWindow.Resources>
<ResourceDictionary>
<Panel x:Key="RootWindowTitlebar" Height="31" HorizontalAlignment="Stretch" Background="Red">
<TextBlock>Test</TextBlock>
</Panel>
</ResourceDictionary>
</controls:CoreWindow.Resources>
<!-- Use a panel here so the main window can host ContentDialogs -->
<Panel>
<ContentControl Content="{Binding}" />
</Panel>
</Window>
</controls:CoreWindow>

View File

@ -1,20 +1,30 @@
using Artemis.UI.Screens.Root;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using FluentAvalonia.Core.ApplicationModel;
namespace Artemis.UI
{
public class MainWindow : ReactiveWindow<RootViewModel>
public class MainWindow : ReactiveCoreWindow<RootViewModel>
{
public MainWindow()
{
InitializeComponent();
SetupTitlebar();
#if DEBUG
this.AttachDevTools();
#endif
}
private void SetupTitlebar()
{
object? titleBar = this.FindResource("RootWindowTitlebar");
if (titleBar != null)
SetTitleBar((IControl) titleBar);
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);

View File

@ -3,6 +3,7 @@ using Artemis.Core;
using Artemis.UI.Screens.Device;
using Artemis.UI.Screens.Plugins;
using Artemis.UI.Screens.ProfileEditor;
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
using Artemis.UI.Screens.Settings;
using Artemis.UI.Screens.Sidebar;
using Artemis.UI.Screens.SurfaceEditor;
@ -54,5 +55,7 @@ namespace Artemis.UI.Ninject.Factories
public interface IProfileEditorVmFactory : IVmFactory
{
ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen);
FolderTreeItemViewModel FolderTreeItemViewModel(Folder folder);
LayerTreeItemViewModel LayerTreeItemViewModel(Layer layer);
}
}

View File

@ -0,0 +1,80 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using FluentAvalonia.Interop;
using FluentAvalonia.UI.Controls;
using ReactiveUI;
namespace Artemis.UI
{
/// <summary>
/// A ReactiveUI <see cref="Window"/> that implements the <see cref="IViewFor{TViewModel}"/> interface and will
/// activate your ViewModel automatically if the view model implements <see cref="IActivatableViewModel"/>. When
/// the DataContext property changes, this class will update the ViewModel property with the new DataContext value,
/// and vice versa.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveCoreWindow<TViewModel> : CoreWindow, IViewFor<TViewModel> where TViewModel : class
{
public static readonly StyledProperty<TViewModel?> ViewModelProperty = AvaloniaProperty
.Register<ReactiveCoreWindow<TViewModel>, TViewModel?>(nameof(ViewModel));
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveCoreWindow{TViewModel}"/> class.
/// </summary>
public ReactiveCoreWindow()
{
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.GetObservable(DataContextProperty).Subscribe(OnDataContextChanged);
this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged);
// TODO Remove
Win32Interop.OSVERSIONINFOEX version = default;
Win32Interop.RtlGetVersion(ref version);
if (version.MajorVersion == 10)
PseudoClasses.Add(":windows10");
}
/// <summary>
/// The ViewModel.
/// </summary>
public TViewModel? ViewModel
{
get => GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (TViewModel?)value;
}
private void OnDataContextChanged(object? value)
{
if (value is TViewModel viewModel)
{
ViewModel = viewModel;
}
else
{
ViewModel = null;
}
}
private void OnViewModelChanged(object? value)
{
if (value == null)
{
ClearValue(DataContextProperty);
}
else if (DataContext != value)
{
DataContext = value;
}
}
}
}

View File

@ -1,4 +1,4 @@
<Window xmlns="https://github.com/avaloniaui"
<controls:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -67,4 +67,4 @@
</reactiveUi:RoutedViewHost>
</controls:NavigationView>
</Window>
</controls:CoreWindow>

View File

@ -12,7 +12,7 @@ using ReactiveUI;
namespace Artemis.UI.Screens.Debugger
{
public class DebugView : ReactiveWindow<DebugViewModel>
public class DebugView : ReactiveCoreWindow<DebugViewModel>
{
public DebugView()
{

View File

@ -1,8 +1,9 @@
<Window xmlns="https://github.com/avaloniaui"
<controls1:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
x:Class="Artemis.UI.Screens.Device.DevicePropertiesView"
Icon="/Assets/Images/Logo/bow.ico"
@ -62,4 +63,4 @@
</Border>
</Grid>
</Window>
</controls1:CoreWindow>

View File

@ -4,7 +4,7 @@ using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device
{
public partial class DevicePropertiesView : ReactiveWindow<DevicePropertiesViewModel>
public partial class DevicePropertiesView : ReactiveCoreWindow<DevicePropertiesViewModel>
{
public DevicePropertiesView()
{

View File

@ -1,7 +1,8 @@
<Window xmlns="https://github.com/avaloniaui"
<controls:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Plugins.PluginSettingsWindowView"
Icon="/Assets/Images/Logo/bow.ico"
@ -12,4 +13,4 @@
<Panel>
<ContentControl Content="{Binding ConfigurationViewModel}"></ContentControl>
</Panel>
</Window>
</controls:CoreWindow>

View File

@ -8,7 +8,7 @@ using ReactiveUI;
namespace Artemis.UI.Screens.Plugins
{
public class PluginSettingsWindowView : ReactiveWindow<PluginSettingsWindowViewModel>
public class PluginSettingsWindowView : ReactiveCoreWindow<PluginSettingsWindowViewModel>
{
public PluginSettingsWindowView()
{

View File

@ -0,0 +1,36 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView">
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<Button Grid.Column="0"
ToolTip.Tip="{Binding BrokenState}"
IsVisible="{Binding BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
Classes="icon-button icon-button-small"
Foreground="White"
Background="#E74C4C"
BorderBrush="#E74C4C"
Command="{Binding ShowBrokenStateExceptions}">
<avalonia:MaterialIcon Kind="AlertCircle" />
</Button>
<avalonia:MaterialIcon Grid.Column="1"
Kind="Folder"
Margin="5 0"
IsVisible="{Binding !IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" />
<avalonia:MaterialIcon Grid.Column="1"
Kind="FolderOpen"
Margin="5 0"
IsVisible="{Binding IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" />
<TextBlock Grid.Column="2" Text="{Binding Folder.Name}" VerticalAlignment="Center" />
<ToggleButton Grid.Column="3"
Classes="icon-button icon-button-small"
ToolTip.Tip="Toggle suspended state"
IsChecked="{Binding !Folder.Suspended}"
VerticalAlignment="Center">
<avalonia:MaterialIcon Kind="Pause" />
</ToggleButton>
</Grid>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public partial class FolderTreeItemView : UserControl
{
public FolderTreeItemView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using Artemis.Core;
using Artemis.UI.Ninject.Factories;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public class FolderTreeItemViewModel : TreeItemViewModel
{
public Folder Folder { get; }
public FolderTreeItemViewModel(Folder folder, IProfileEditorVmFactory profileEditorVmFactory)
{
Folder = folder;
Children = new List<TreeItemViewModel>();
foreach (ProfileElement profileElement in folder.Children)
{
if (profileElement is Folder childFolder)
Children.Add(profileEditorVmFactory.FolderTreeItemViewModel(childFolder));
else if (profileElement is Layer layer)
Children.Add(profileEditorVmFactory.LayerTreeItemViewModel(layer));
}
}
public List<TreeItemViewModel> Children { get; }
}
}

View File

@ -0,0 +1,29 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.LayerTreeItemView">
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<Button Grid.Column="0"
ToolTip.Tip="{Binding BrokenState}"
IsVisible="{Binding BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
Classes="icon-button icon-button-small"
Foreground="White"
Background="#E74C4C"
BorderBrush="#E74C4C"
Command="{Binding ShowBrokenStateExceptions}">
<avalonia:MaterialIcon Kind="AlertCircle" />
</Button>
<avalonia:MaterialIcon Grid.Column="1" Kind="{Binding Layer.LayerBrush.Descriptor.Icon}" Margin="5 0"/>
<TextBlock Grid.Column="2" Text="{Binding Layer.Name}" VerticalAlignment="Center" />
<ToggleButton Grid.Column="3"
Classes="icon-button icon-button-small"
ToolTip.Tip="Toggle suspended state"
IsChecked="{Binding Layer.Suspended}"
VerticalAlignment="Center">
<avalonia:MaterialIcon Kind="Pause" />
</ToggleButton>
</Grid>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public partial class LayerTreeItemView : UserControl
{
public LayerTreeItemView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -0,0 +1,14 @@
using Artemis.Core;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public class LayerTreeItemViewModel : TreeItemViewModel
{
public Layer Layer { get; }
public LayerTreeItemViewModel(Layer layer)
{
Layer = layer;
}
}
}

View File

@ -0,0 +1,15 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.ProfileTreeView">
<TreeView Items="{Binding TreeItems}" Classes="no-right-margin">
<TreeView.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<ContentControl Content="{Binding}"/>
</TreeDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public partial class ProfileTreeView : ReactiveUserControl<ProfileTreeViewModel>
{
public ProfileTreeView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables;
using Artemis.Core;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Services;
using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public class ProfileTreeViewModel : ActivatableViewModelBase
{
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
public ProfileTreeViewModel(IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
{
_profileEditorVmFactory = profileEditorVmFactory;
this.WhenActivated(d => profileEditorService.CurrentProfileConfiguration.WhereNotNull().Subscribe(Repopulate).DisposeWith(d));
}
public ObservableCollection<TreeItemViewModel> TreeItems { get; } = new();
private void Repopulate(ProfileConfiguration profileConfiguration)
{
if (TreeItems.Any())
TreeItems.Clear();
if (profileConfiguration.Profile == null)
return;
foreach (ProfileElement profileElement in profileConfiguration.Profile.GetRootFolder().Children)
{
if (profileElement is Folder folder)
TreeItems.Add(_profileEditorVmFactory.FolderTreeItemViewModel(folder));
else if (profileElement is Layer layer)
TreeItems.Add(_profileEditorVmFactory.LayerTreeItemViewModel(layer));
}
}
}
}

View File

@ -0,0 +1,8 @@
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{
public abstract class TreeItemViewModel : ActivatableViewModelBase
{
}
}

View File

@ -253,7 +253,7 @@
<Grid Grid.Row="1" Grid.Column="2" RowDefinitions="*,Auto,*">
<Border Grid.Row="0" Classes="card card-condensed" Margin="4 0 4 4">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Profile elements</TextBlock>
<ContentControl Content="{Binding ProfileTreeViewModel}" />
</Border>
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />

View File

@ -1,6 +1,7 @@
using System;
using System.Reactive.Disposables;
using Artemis.Core;
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
using Artemis.UI.Screens.ProfileEditor.VisualEditor;
using Artemis.UI.Services;
using ReactiveUI;
@ -12,13 +13,16 @@ namespace Artemis.UI.Screens.ProfileEditor
private ProfileConfiguration? _profile;
/// <inheritdoc />
public ProfileEditorViewModel(IScreen hostScreen, VisualEditorViewModel visualEditorViewModel, IProfileEditorService profileEditorService) : base(hostScreen, "profile-editor")
public ProfileEditorViewModel(IScreen hostScreen, IProfileEditorService profileEditorService, VisualEditorViewModel visualEditorViewModel, ProfileTreeViewModel profileTreeViewModel)
: base(hostScreen, "profile-editor")
{
VisualEditorViewModel = visualEditorViewModel;
ProfileTreeViewModel = profileTreeViewModel;
this.WhenActivated(disposables => { profileEditorService.CurrentProfileConfiguration.WhereNotNull().Subscribe(p => Profile = p).DisposeWith(disposables); });
}
public VisualEditorViewModel VisualEditorViewModel { get; }
public ProfileTreeViewModel ProfileTreeViewModel { get; }
public ProfileConfiguration? Profile
{

View File

@ -1,4 +1,4 @@
<Window xmlns="https://github.com/avaloniaui"
<controls1:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -8,6 +8,7 @@
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar"
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="850"
x:Class="Artemis.UI.Screens.Sidebar.ProfileConfigurationEditView"
Title="{Binding DisplayName}"
@ -181,4 +182,4 @@
</Grid>
</Grid>
</Window>
</controls1:CoreWindow>

View File

@ -4,7 +4,7 @@ using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Sidebar
{
public partial class ProfileConfigurationEditView : ReactiveWindow<ProfileConfigurationEditViewModel>
public partial class ProfileConfigurationEditView : ReactiveCoreWindow<ProfileConfigurationEditViewModel>
{
public ProfileConfigurationEditView()
{

View File

@ -10,6 +10,7 @@
</Styles.Resources>
<!-- Third party styles -->
<styling:FluentAvaloniaTheme RequestedTheme="Dark" />
<!-- <FluentTheme Mode="Dark"></FluentTheme> -->
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
<StyleInclude Source="avares://Artemis.UI.Shared/Styles/Artemis.axaml" />
</Styles>

View File

@ -76,9 +76,9 @@
},
"FluentAvaloniaUI": {
"type": "Direct",
"requested": "[1.1.6, )",
"resolved": "1.1.6",
"contentHash": "EJukyiTmEVhaYlHdntFMyQKI4+u772rSClKYQqJRfkTb1NoJXLqiIVqMjx8ZQ0pxnfih+6CZ7+x82lfrGHIPUw==",
"requested": "[1.1.7, )",
"resolved": "1.1.7",
"contentHash": "Hco3+M09A7rDknaYu5CcyGhUOqGj5mebrFzjZVGjW5YBYiMiV+x0vl2Fn6oIfXxhKgg1i70tTwQCtW/1GWFJeA==",
"dependencies": {
"Avalonia": "0.10.10",
"Avalonia.Desktop": "0.10.10",
@ -126,12 +126,12 @@
},
"Splat.Ninject": {
"type": "Direct",
"requested": "[13.1.63, )",
"resolved": "13.1.63",
"contentHash": "rTF0HSa6p8nxrXj2hwVgkutcTDJUXY34sY+zYK4ky65b7a0ROL8kdiYyxVVLE4Lq31N5Rcd4bBbqlPkgwZguww==",
"requested": "[14.1.1, )",
"resolved": "14.1.1",
"contentHash": "lmhjY5yRKL6SgkwY0kEtnHI8JERYhRwFiOk+NgvOUtGYzVm/RRm1OrgrN+kPKzmuvsUrodx6FYTHrSkHL2I8Yg==",
"dependencies": {
"Ninject": "3.3.4",
"Splat": "13.1.63"
"Splat": "14.1.1"
}
},
"Avalonia.Angle.Windows.Natives": {
@ -705,8 +705,8 @@
},
"Splat": {
"type": "Transitive",
"resolved": "13.1.63",
"contentHash": "7iW45RA7AbSlQPCgdokmysva5PGd6iBUhuNkC0XD73LF9dxfTkKeo3wZkohU7nvspDhJ7PJsYHvDtxIt5bMQ8Q=="
"resolved": "14.1.1",
"contentHash": "bKQtKu57w+iJ1T+WDyDdNq+LBNVdmNu2i0vGNyUdtmg4TEIEFiX2GfPusNEAW2QOfxyDE7i4+xTxbOKZr/4jhg=="
},
"Svg.Custom": {
"type": "Transitive",
@ -1698,7 +1698,7 @@
"Avalonia.Xaml.Behaviors": "0.10.10.4",
"Avalonia.Xaml.Interactions": "0.10.10.4",
"Avalonia.Xaml.Interactivity": "0.10.10.4",
"FluentAvaloniaUI": "1.1.6",
"FluentAvaloniaUI": "1.1.7",
"Material.Icons.Avalonia": "1.0.2",
"ReactiveUI.Validation": "2.2.1"
}