Add design mode

This commit is contained in:
Robert committed 2026-07-31 15:30:11 +02:00
1 parent 5a681a0480
commit eb812cb5e1
50 files changed
+782 -257

No files matched your search

@@ -1,25 +1,25 @@
namespace Artemis.Core;
/// <summary>
/// Represents a configuration item that accepts boolean input from the user.
/// Represents a configuration item that accepts boolean input from the user.
/// </summary>
public class ConfigurationBooleanItem : ConfigurationInputItem<bool>
{
/// <summary>
/// Gets or sets the display text shown when the boolean value is true.
/// Gets or sets the display text shown when the boolean value is true.
/// </summary>
public required string TrueText
public string TrueText
{
get;
set => SetAndNotify(ref field, value);
}
} = "Yes";
/// <summary>
/// Gets or sets the display text shown when the boolean value is false.
/// Gets or sets the display text shown when the boolean value is false.
/// </summary>
public required string FalseText
public string FalseText
{
get;
set => SetAndNotify(ref field, value);
}
} = "No";
}
@@ -3,13 +3,13 @@
namespace Artemis.Core;
/// <summary>
/// Represents a generic base class for configuration items that accept user input.
/// Represents a generic base class for configuration items that accept user input.
/// </summary>
/// <typeparam name="T">The type of the value that this configuration item holds.</typeparam>
public class ConfigurationInputItem<T> : CorePropertyChanged, IConfigurationItem
{
/// <summary>
/// Gets or sets the display name of the configuration item.
/// Gets or sets the display name of the configuration item.
/// </summary>
public required string Name
{
@@ -18,7 +18,7 @@ public class ConfigurationInputItem<T> : CorePropertyChanged, IConfigurationItem
}
/// <summary>
/// Gets or sets the description text that explains the purpose of this configuration item.
/// Gets or sets the description text that explains the purpose of this configuration item.
/// </summary>
public string? Description
{
@@ -27,7 +27,7 @@ public class ConfigurationInputItem<T> : CorePropertyChanged, IConfigurationItem
}
/// <summary>
/// Gets or sets the current value of the configuration item.
/// Gets or sets the current value of the configuration item.
/// </summary>
public T? Value
{
@@ -36,8 +36,17 @@ public class ConfigurationInputItem<T> : CorePropertyChanged, IConfigurationItem
}
/// <summary>
/// Gets or sets the collection of dropdown values for this configuration item.
/// When populated, the configuration item will be rendered as a dropdown/combo box.
/// Gets or sets the default value of the configuration item.
/// </summary>
public T? DefaultValue
{
get;
set => SetAndNotify(ref field, value);
}
/// <summary>
/// Gets or sets the collection of dropdown values for this configuration item.
/// When populated, the configuration item will be rendered as a dropdown/combo box.
/// </summary>
public ObservableCollection<ConfigurationDropdownValue<T>>? DropdownValues
{
@@ -1,11 +1,25 @@
namespace Artemis.Core;
/// <summary>
/// Represents a configuration item that accepts numeric input from the user.
/// Represents a configuration item that accepts numeric input from the user.
/// </summary>
public class ConfigurationNumericItem : ConfigurationInputItem<Numeric>
{
public Numeric? Minimum { get; set; }
public Numeric? Maximum { get; set; }
public bool Slider { get; set; }
public Numeric? Minimum
{
get;
set => SetAndNotify(ref field, value);
}
public Numeric? Maximum
{
get;
set => SetAndNotify(ref field, value);
}
public bool Slider
{
get;
set => SetAndNotify(ref field, value);
}
}
@@ -3,12 +3,26 @@
namespace Artemis.Core;
/// <summary>
/// Represents a configuration section that contains a collection of configuration items.
/// Represents a configuration section that contains a collection of configuration items.
/// </summary>
public class ConfigurationSection : CorePropertyChanged
{
/// <summary>
/// Gets or sets the name of the configuration section.
/// Creates a new instance of the <see cref="ProfileConfiguration" /> class.
/// </summary>
/// <param name="profileConfiguration">The profile configuration this section belongs to.</param>
public ConfigurationSection(ProfileConfiguration profileConfiguration)
{
ProfileConfiguration = profileConfiguration;
}
/// <summary>
/// Gets the profile configuration this section belongs to.
/// </summary>
public ProfileConfiguration ProfileConfiguration { get; }
/// <summary>
/// Gets or sets the name of the configuration section.
/// </summary>
public required string Name
{
@@ -17,7 +31,7 @@ public class ConfigurationSection : CorePropertyChanged
}
/// <summary>
/// Gets the collection of configuration items in this section.
/// Gets the collection of configuration items in this section.
/// </summary>
public ObservableCollection<IConfigurationItem> Items { get; } = [];
}
@@ -13,7 +13,7 @@ namespace Artemis.Core;
public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable, IPluginFeatureDependent
{
/// <summary>
/// Represents an empty profile.
/// Represents an empty profile.
/// </summary>
public static readonly ProfileConfiguration Empty = new(ProfileCategory.Empty, "Empty", "Empty");
@@ -147,7 +147,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
}
/// <summary>
/// Gets or sets a boolean indicating whether this profile should fade in and out when enabling or disabling
/// Gets or sets a boolean indicating whether this profile should fade in and out when enabling or disabling
/// </summary>
public bool FadeInAndOut
{
@@ -156,7 +156,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
}
/// <summary>
/// Gets or sets a boolean indicating whether this profile is configurable via its <see cref="ConfigurationSections"/>.
/// Gets or sets a boolean indicating whether this profile is configurable via its <see cref="ConfigurationSections" />.
/// </summary>
public bool IsConfigurable
{
@@ -251,19 +251,6 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
return $"[ProfileConfiguration] {nameof(Name)}: {Name}";
}
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
if (_disposed)
throw new ObjectDisposedException("ProfileConfiguration");
if (Profile == null)
throw new InvalidOperationException("Cannot determine feature dependencies when the profile is not loaded.");
return ActivationCondition.GetFeatureDependencies()
.Concat(Profile.GetFeatureDependencies())
.Concat(Module != null ? [Module] : []);
}
internal void LoadModules(List<Module> enabledModules)
{
if (_disposed)
@@ -280,6 +267,19 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
ActivationCondition.Dispose();
}
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
if (_disposed)
throw new ObjectDisposedException("ProfileConfiguration");
if (Profile == null)
throw new InvalidOperationException("Cannot determine feature dependencies when the profile is not loaded.");
return ActivationCondition.GetFeatureDependencies()
.Concat(Profile.GetFeatureDependencies())
.Concat(Module != null ? [Module] : []);
}
#region Implementation of IStorageModel
/// <inheritdoc />
@@ -305,27 +305,27 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
// Placeholder configuration sections
ConfigurationSections.Clear();
ConfigurationSections.Add(new ConfigurationSection()
ConfigurationSections.Add(new ConfigurationSection(this)
{
Name = "General",
Name = "General"
});
ConfigurationSections.Add(new ConfigurationSection()
ConfigurationSections.Add(new ConfigurationSection(this)
{
Name = "Other",
Name = "Other"
});
ConfigurationSections.Add(new ConfigurationSection()
ConfigurationSections.Add(new ConfigurationSection(this)
{
Name = "Something else",
Name = "Something else"
});
ConfigurationSections[0].Items.Add(new ConfigurationTextItem() {Text = "This is a placeholder text item in the General section."});
ConfigurationSections[0].Items.Add(new ConfigurationNumericItem() {Name = "Numeric item", Description = "This one also has a description"});
ConfigurationSections[0].Items.Add(new ConfigurationBooleanItem() {Name = "Do the thing?", TrueText = "Absolutely", FalseText = "Nope"});
ConfigurationSections[1].Items.Add(new ConfigurationTextItem() {Text = "This is a placeholder text item in the Other section."});
ConfigurationSections[2].Items.Add(new ConfigurationTextItem() {Text = "This is a placeholder text item in the Something else section."});
ConfigurationSections[2].Items.Add(new ConfigurationTextItem() {Text = "This is another placeholder text item in the Something else section."});
ConfigurationSections[2].Items.Add(new ConfigurationNumericItem() {Name = "Numeric item", Description = "This one uses a slider", Minimum = 0, Maximum = 10, Slider = true});
ConfigurationSections[2].Items.Add(new ConfigurationColorGradientItem() {Name = "Color gradient"});
ConfigurationSections[2].Items.Add(new ConfigurationSKColorItem() {Name = "A simple color", Description = "Again with a description"});
ConfigurationSections[0].Items.Add(new ConfigurationTextItem {Text = "This is a placeholder text item in the General section."});
ConfigurationSections[0].Items.Add(new ConfigurationNumericItem {Name = "Numeric item", Description = "This one also has a description"});
ConfigurationSections[0].Items.Add(new ConfigurationBooleanItem {Name = "Do the thing?", TrueText = "Absolutely", FalseText = "Nope"});
ConfigurationSections[1].Items.Add(new ConfigurationTextItem {Text = "This is a placeholder text item in the Other section."});
ConfigurationSections[2].Items.Add(new ConfigurationTextItem {Text = "This is a placeholder text item in the Something else section."});
ConfigurationSections[2].Items.Add(new ConfigurationTextItem {Text = "This is another placeholder text item in the Something else section."});
ConfigurationSections[2].Items.Add(new ConfigurationNumericItem {Name = "Numeric item", Description = "This one uses a slider", Minimum = 0, Maximum = 10, Slider = true});
ConfigurationSections[2].Items.Add(new ConfigurationColorGradientItem {Name = "Color gradient"});
ConfigurationSections[2].Items.Add(new ConfigurationSKColorItem {Name = "A simple color", Description = "Again with a description"});
}
/// <inheritdoc />
+23 -20
View File
@@ -3,7 +3,7 @@
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia">
<!-- Preview -->
<Design.PreviewWith>
<Border Padding="20">
<Border Padding="20">
<StackPanel>
<TextBlock Margin="0 5 0 0">Button.icon-button</TextBlock>
<Button Classes="icon-button">
@@ -13,7 +13,7 @@
<avalonia:MaterialIcon Kind="Cog" />
</Button>
<TextBlock Margin="0 5 0 0">Button.icon-button icon-button-small</TextBlock>
<TextBlock Margin="0 5 0 0">Button.icon-button icon-button-small</TextBlock>
<Button Classes="icon-button icon-button-small">
<avalonia:MaterialIcon Kind="Cog" />
</Button>
@@ -34,15 +34,15 @@
</HyperlinkButton>
<TextBlock Margin="0 5 0 0">Button.window-button</TextBlock>
<Button Classes="title-bar-button">
<avalonia:MaterialIcon Kind="WindowMinimize" />
</Button>
<TextBlock Margin="0 5 0 0">Button.window-button</TextBlock>
<Button Classes="title-bar-button">
<avalonia:MaterialIcon Kind="WindowMinimize" />
</Button>
<Button Classes="icon-button">
<avalonia:MaterialIcon Kind="Cog" />
</Button>
<Button Classes="danger">
Oohohoho daanger!
</Button>
@@ -51,6 +51,9 @@
</Design.PreviewWith>
<!-- Styles -->
<Style Selector=":is(Button).icon-button-outlined">
<Setter Property="Padding" Value="7" />
</Style>
<Style Selector=":is(Button).icon-button">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
@@ -58,7 +61,7 @@
</Style>
<Style Selector=":is(Button).icon-button:pointerover /template/ Border#BorderElement">
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Style>
<Style Selector=":is(Button).icon-button:disabled /template/ Border#BorderElement">
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
@@ -79,7 +82,7 @@
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AppBarButtonForegroundDisabled}" />
</Style>
<Style Selector=":is(Button).icon-button-small">
<Style Selector=":is(Button).icon-button-small">
<Setter Property="Padding" Value="4" />
</Style>
<Style Selector=":is(Button).icon-button-small avalonia|MaterialIcon">
@@ -97,21 +100,21 @@
</Style>
<Style Selector="Button.title-bar-button">
<Setter Property="Width" Value="46"></Setter>
<Setter Property="Height" Value="30"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="CornerRadius" Value="0"></Setter>
<Setter Property="Margin" Value="0"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="30" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.title-bar-button:pointerover">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="Background" Value="Red" />
</Style>
<Style Selector="Button.danger">
<Setter Property="Background" Value="#D64848"></Setter>
<Setter Property="Background" Value="#D64848" />
</Style>
<!-- <Style Selector="Button.danger:pointerover"> -->
<!-- <Style Selector="^ /template/ controls|FABorder#Root"> -->
<!-- <Setter Property="Background" Value="#D65757"/> -->
@@ -0,0 +1,26 @@
<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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationBooleanItemView"
x:DataType="items:ConfigurationBooleanItemViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{CompiledBinding Item.Value}"
OnContent="{CompiledBinding Item.TrueText}"
OffContent="{CompiledBinding Item.FalseText}"
MinWidth="0"
Margin="0 -10"
FlowDirection="RightToLeft" />
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationBooleanItemView : ReactiveUserControl<ConfigurationStringItemViewModel>
{
public ConfigurationBooleanItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationBooleanItemViewModel : ActivatableViewModelBase
{
public ConfigurationBooleanItemViewModel(ConfigurationBooleanItem item)
{
Item = item;
}
public ConfigurationBooleanItem Item { get; }
}
@@ -0,0 +1,24 @@
<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:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationColorGradientItemView"
x:DataType="items:ConfigurationColorGradientItemViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<gradientPicker:GradientPickerButton Width="150"
ColorGradient="{CompiledBinding Item.Value}"
VerticalAlignment="Center" />
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationColorGradientItemView : ReactiveUserControl<ConfigurationColorGradientItemViewModel>
{
public ConfigurationColorGradientItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationColorGradientItemViewModel : ActivatableViewModelBase
{
public ConfigurationColorGradientItemViewModel(ConfigurationColorGradientItem item)
{
Item = item;
}
public ConfigurationColorGradientItem Item { get; }
}
@@ -0,0 +1,32 @@
<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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationNumericItemView"
x:DataType="items:ConfigurationNumericItemViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:NumberBox Width="150" IsVisible="{CompiledBinding !Item.Slider}">
<Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding Item.Value}" />
</Interaction.Behaviors>
</controls:NumberBox>
<Slider Minimum="{CompiledBinding Item.Minimum}"
Maximum="{CompiledBinding Item.Maximum}"
Width="150"
IsVisible="{CompiledBinding Item.Slider}"
Value="{CompiledBinding Item.Value, Mode=TwoWay}" />
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationNumericItemView : ReactiveUserControl<ConfigurationStringItemViewModel>
{
public ConfigurationNumericItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationNumericItemViewModel : ActivatableViewModelBase
{
public ConfigurationNumericItemViewModel(ConfigurationNumericItem item)
{
Item = item;
}
public ConfigurationNumericItem Item { get; }
}
@@ -0,0 +1,25 @@
<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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationSKColorItemView"
x:DataType="items:ConfigurationSKColorItemViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:ColorPickerButton Color="{CompiledBinding Item.Value, Converter={StaticResource SKColorToColorConverter}}"
ShowAcceptDismissButtons="False"
FlyoutPlacement="Right" />
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationSKColorItemView : ReactiveUserControl<ConfigurationStringItemViewModel>
{
public ConfigurationSKColorItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationSKColorItemViewModel : ActivatableViewModelBase
{
public ConfigurationSKColorItemViewModel(ConfigurationSKColorItem item)
{
Item = item;
}
public ConfigurationSKColorItem Item { get; }
}
@@ -0,0 +1,21 @@
<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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationStringItemView"
x:DataType="items:ConfigurationStringItemViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Text="{CompiledBinding Item.Value, Mode=TwoWay}" MinWidth="150" />
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationStringItemView : ReactiveUserControl<ConfigurationStringItemViewModel>
{
public ConfigurationStringItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationStringItemViewModel : ActivatableViewModelBase
{
public ConfigurationStringItemViewModel(ConfigurationStringItem item)
{
Item = item;
}
public ConfigurationStringItem Item { get; }
}
@@ -2,9 +2,9 @@
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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationTextItemDesignDesignView"
x:DataType="items:ConfigurationTextItemDesignViewModel">
<TextBox Text="{CompiledBinding Item.Text}" />
</UserControl>
x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationTextItemView"
x:DataType="items:ConfigurationTextItemViewModel">
<TextBlock Text="{CompiledBinding Item.Text}" />
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public partial class ConfigurationTextItemView : ReactiveUserControl<ConfigurationTextItemViewModel>
{
public ConfigurationTextItemView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
public class ConfigurationTextItemViewModel : ActivatableViewModelBase
{
public ConfigurationTextItemViewModel(ConfigurationTextItem item)
{
Item = item;
}
public ConfigurationTextItem Item { get; }
}
@@ -3,24 +3,30 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationBooleanItemDesignView"
x:DataType="items:ConfigurationBooleanItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBox Text="{CompiledBinding BooleanItem.Name}" Watermark="Name" />
<TextBox Text="{CompiledBinding BooleanItem.Description}" Watermark="Description" />
<Grid ColumnDefinitions="*,*" ColumnSpacing="5">
<TextBox Grid.Column="0" Text="{CompiledBinding BooleanItem.TrueText}" Watermark="Enabled label" />
<TextBox Grid.Column="1" Text="{CompiledBinding BooleanItem.FalseText}" Watermark="Disabled label" />
</Grid>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{CompiledBinding Item.Value}"
OnContent="{CompiledBinding Item.TrueText}"
OffContent="{CompiledBinding Item.FalseText}"
MinWidth="0"
Margin="0 -10"
FlowDirection="RightToLeft"/>
<StackPanel Grid.Row="0" Grid.Column="1">
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<ToggleSwitch IsChecked="{CompiledBinding BooleanItem.Value}"
OnContent="{CompiledBinding BooleanItem.TrueText}"
OffContent="{CompiledBinding BooleanItem.FalseText}"
Width="150"
Margin="0 -6 0 0"
HorizontalAlignment="Left" />
</StackPanel>
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
</UserControl>
@@ -1,5 +1,4 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationBooleanItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationBooleanItemDesignViewModel(ConfigurationBooleanItem item, ConfigurationSection configurationSection) : ConfigurationItemDesignViewModel(item, configurationSection)
{
public ConfigurationBooleanItem Item { get; }
public ConfigurationBooleanItemDesignViewModel(ConfigurationBooleanItem item)
{
Item = item;
}
public ConfigurationBooleanItem BooleanItem { get; } = item;
}
@@ -4,21 +4,23 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationColorGradientItemDesignView"
x:DataType="items:ConfigurationColorGradientItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBox Text="{CompiledBinding GradientItem.Name}" Watermark="Name" />
<TextBox Text="{CompiledBinding GradientItem.Description}" Watermark="Description" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<gradientPicker:GradientPickerButton Width="150"
ColorGradient="{CompiledBinding Item.Value}"
VerticalAlignment="Center"/>
ColorGradient="{CompiledBinding GradientItem.Value}"
VerticalAlignment="Center" />
</StackPanel>
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
</UserControl>
@@ -1,5 +1,4 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,17 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationColorGradientItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationColorGradientItemDesignViewModel : ConfigurationItemDesignViewModel
{
public ConfigurationColorGradientItemDesignViewModel(ConfigurationColorGradientItem item)
public ConfigurationColorGradientItemDesignViewModel(ConfigurationColorGradientItem item, ConfigurationSection configurationSection) : base(item, configurationSection)
{
Item = item;
// The gradient picker doesn't handle null values well
item.DefaultValue ??= ColorGradient.GetUnicornBarf();
item.Value ??= ColorGradient.GetUnicornBarf();
GradientItem = item;
}
public ConfigurationColorGradientItem Item { get; }
public ConfigurationColorGradientItem GradientItem { get; }
}
@@ -5,28 +5,36 @@
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationNumericItemDesignView"
x:DataType="items:ConfigurationNumericItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBox Text="{CompiledBinding NumericItem.Name}" Watermark="Name" />
<TextBox Text="{CompiledBinding NumericItem.Description}" Watermark="Description" />
<ToggleSwitch IsChecked="{CompiledBinding NumericItem.Slider}"
OnContent="Slider"
OffContent="Number box"
MinWidth="0"
Margin="0 -8" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:NumberBox Width="150" IsVisible="{CompiledBinding !Item.Slider}">
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Top">
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<controls:NumberBox Width="150" IsVisible="{CompiledBinding !NumericItem.Slider}">
<Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding Item.Value}" />
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding NumericItem.Value}" />
</Interaction.Behaviors>
</controls:NumberBox>
<Slider Minimum="{CompiledBinding Item.Minimum}"
Maximum="{CompiledBinding Item.Maximum}"
Width="150"
IsVisible="{CompiledBinding Item.Slider}"
Value="{CompiledBinding Item.Value, Mode=TwoWay}" />
<Slider Minimum="{CompiledBinding NumericItem.Minimum}"
Maximum="{CompiledBinding NumericItem.Maximum}"
Width="150"
Margin="0 -5 0 0"
IsVisible="{CompiledBinding NumericItem.Slider}"
Value="{CompiledBinding NumericItem.Value, Mode=TwoWay}" />
</StackPanel>
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
@@ -1,5 +1,4 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationNumericItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationNumericItemDesignViewModel(ConfigurationNumericItem item, ConfigurationSection configurationSection) : ConfigurationItemDesignViewModel(item, configurationSection)
{
public ConfigurationNumericItem Item { get; }
public ConfigurationNumericItemDesignViewModel(ConfigurationNumericItem item)
{
Item = item;
}
public ConfigurationNumericItem NumericItem { get; } = item;
}
@@ -4,22 +4,25 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationSKColorItemDesignView"
x:DataType="items:ConfigurationSKColorItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBox Text="{CompiledBinding ColorItem.Name}" Watermark="Name" />
<TextBox Text="{CompiledBinding ColorItem.Description}" Watermark="Description" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:ColorPickerButton Color="{CompiledBinding Item.Value, Converter={StaticResource SKColorToColorConverter}}"
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<controls:ColorPickerButton Color="{CompiledBinding ColorItem.Value, Converter={StaticResource SKColorToColorConverter}}"
Width="150"
ShowAcceptDismissButtons="False"
FlyoutPlacement="Right" />
</StackPanel>
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
@@ -1,5 +1,4 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationSKColorItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationSKColorItemDesignViewModel(ConfigurationSKColorItem item, ConfigurationSection configurationSection) : ConfigurationItemDesignViewModel(item, configurationSection)
{
public ConfigurationSKColorItemDesignViewModel(ConfigurationSKColorItem item)
{
Item = item;
}
public ConfigurationSKColorItem Item { get; }
public ConfigurationSKColorItem ColorItem { get; } = item;
}
@@ -3,19 +3,22 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationStringItemDesignView"
x:DataType="items:ConfigurationStringItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" />
<TextBlock Classes="subtitle"
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBox Text="{CompiledBinding StringItem.Name}" Watermark="Name" />
<TextBox Text="{CompiledBinding StringItem.Description}" Watermark="Description" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Text="{CompiledBinding Item.Value, Mode=TwoWay}" MinWidth="150" />
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<TextBox Text="{CompiledBinding StringItem.Value, Mode=TwoWay}" MinWidth="150" />
</StackPanel>
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
@@ -1,5 +1,4 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationStringItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationStringItemDesignViewModel(ConfigurationStringItem item, ConfigurationSection configurationSection) : ConfigurationItemDesignViewModel(item, configurationSection)
{
public ConfigurationStringItem Item { get; }
public ConfigurationStringItemDesignViewModel(ConfigurationStringItem item)
{
Item = item;
}
public ConfigurationStringItem StringItem { get; } = item;
}
@@ -1,12 +0,0 @@
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public partial class ConfigurationTextItemDesignDesignView : ReactiveUserControl<ConfigurationTextItemDesignViewModel>
{
public ConfigurationTextItemDesignDesignView()
{
InitializeComponent();
}
}
@@ -0,0 +1,17 @@
<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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items"
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.DesignPanels.Items.ConfigurationTextItemDesignView"
x:DataType="items:ConfigurationTextItemDesignViewModel">
<Grid ColumnDefinitions="*, Auto" ColumnSpacing="8">
<TextBox Text="{CompiledBinding TextItem.Text}" />
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove" HorizontalAlignment="Right" VerticalAlignment="Top" Classes="icon-button-outlined" Command="{CompiledBinding RemoveItem}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public partial class ConfigurationTextItemDesignView : ReactiveUserControl<ConfigurationTextItemDesignViewModel>
{
public ConfigurationTextItemDesignView()
{
InitializeComponent();
}
}
@@ -3,12 +3,24 @@ using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
public class ConfigurationTextItemDesignViewModel : ActivatableViewModelBase
public class ConfigurationTextItemDesignViewModel(ConfigurationTextItem item, ConfigurationSection configurationSection) : ConfigurationItemDesignViewModel(item, configurationSection)
{
public ConfigurationTextItem Item { get; }
public ConfigurationTextItem TextItem { get; } = item;
}
public ConfigurationTextItemDesignViewModel(ConfigurationTextItem item)
public class ConfigurationItemDesignViewModel : ActivatableViewModelBase
{
protected ConfigurationItemDesignViewModel(IConfigurationItem item, ConfigurationSection configurationSection)
{
Item = item;
ConfigurationSection = configurationSection;
}
public IConfigurationItem Item { get; }
public ConfigurationSection ConfigurationSection { get; }
public void RemoveItem()
{
ConfigurationSection.Items.Remove(Item);
}
}
@@ -0,0 +1,46 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Section.AddConfigurationItemDesignView">
<ListBox SelectionChanged="SelectingItemsControl_OnSelectionChanged">
<ListBoxItem x:Name="BooleanInputItem">
<StackPanel Margin="0 4">
<TextBlock>Boolean input</TextBlock>
<TextBlock Classes="subtitle">Allows the user enable/disable something via a toggle</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ColorGradientInputItem">
<StackPanel Margin="0 4">
<TextBlock>Color gradient input</TextBlock>
<TextBlock Classes="subtitle">Allows the user create a color gradient</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ColorInputItem">
<StackPanel Margin="0 4">
<TextBlock>Color input</TextBlock>
<TextBlock Classes="subtitle">Allows the user to select a color</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="NumericInputItem">
<StackPanel Margin="0 4">
<TextBlock>Numeric input</TextBlock>
<TextBlock Classes="subtitle">Allows the user to a number in either a box or via a slider</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="TextInputItem">
<StackPanel Margin="0 4">
<TextBlock>Text input</TextBlock>
<TextBlock Classes="subtitle">Allows the user to input arbitrary text</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="TextBlockItem">
<StackPanel Margin="0 4">
<TextBlock>Text block</TextBlock>
<TextBlock Classes="subtitle">A simple piece of text, useful for explaining things</TextBlock>
</StackPanel>
</ListBoxItem>
</ListBox>
</UserControl>
@@ -0,0 +1,31 @@
using Artemis.Core;
using Avalonia.Controls;
using ReactiveUI.Avalonia;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Section;
public partial class AddConfigurationItemDesignView : ReactiveUserControl<AddConfigurationItemDesignViewModel>
{
public AddConfigurationItemDesignView()
{
InitializeComponent();
}
private void SelectingItemsControl_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (e.AddedItems[0] is not ListBoxItem item) return;
if (item == BooleanInputItem)
ViewModel?.AddItem(new ConfigurationBooleanItem {Name = "New Boolean"});
else if (item == ColorGradientInputItem)
ViewModel?.AddItem(new ConfigurationColorGradientItem {Name = "New Gradient"});
else if (item == ColorInputItem)
ViewModel?.AddItem(new ConfigurationSKColorItem {Name = "New Color"});
else if (item == NumericInputItem)
ViewModel?.AddItem(new ConfigurationNumericItem {Name = "New Numeric"});
else if (item == TextInputItem)
ViewModel?.AddItem(new ConfigurationStringItem {Name = "New String"});
else if (item == TextBlockItem)
ViewModel?.AddItem(new ConfigurationTextItem {Text = "New Text"});
}
}
@@ -0,0 +1,21 @@
using Artemis.Core;
using Artemis.UI.Shared;
using FluentAvalonia.UI.Controls;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Section;
public class AddConfigurationItemDesignViewModel : ContentDialogViewModelBase
{
public AddConfigurationItemDesignViewModel(ConfigurationSection section)
{
Section = section;
}
public ConfigurationSection Section { get; }
public void AddItem(IConfigurationItem item)
{
Section.Items.Add(item);
ContentDialog?.Hide(ContentDialogResult.Primary);
}
}
@@ -3,20 +3,25 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:section="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Section"
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.DesignPanels.Section.ConfigurationSectionDesignView"
x:DataType="section:ConfigurationSectionDesignViewModel">
<Border Classes="card" VerticalAlignment="Top">
<StackPanel>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}" Text="{CompiledBinding ConfigurationSection.Name}"/>
<Grid ColumnDefinitions="*, Auto" ColumnSpacing="8">
<TextBox Grid.Row="0" Grid.Column="0" Text="{CompiledBinding ConfigurationSection.Name}" Watermark="Section name" FontSize="18" />
<Button Grid.Row="0" Grid.Column="1" ToolTip.Tip="Remove section" Classes="icon-button-outlined" Command="{CompiledBinding RemoveSection}">
<avalonia:MaterialIcon Kind="Trash" />
</Button>
</Grid>
<Border Classes="card-separator" />
<ItemsControl ItemsSource="{CompiledBinding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Classes="device-view-model-container">
<!-- Your existing item template goes here -->
<ContentControl Content="{CompiledBinding}"/>
<ContentControl Content="{CompiledBinding}" />
<Border Classes="card-separator" Name="Separator" />
</StackPanel>
</DataTemplate>
@@ -29,6 +34,10 @@
</Styles>
</ItemsControl.Styles>
</ItemsControl>
<Button HorizontalAlignment="Stretch" Margin="0 8 0 0" ToolTip.Tip="Add item" Command="{CompiledBinding AddItem}">
<avalonia:MaterialIcon Kind="Add" />
</Button>
</StackPanel>
</Border>
</UserControl>
</UserControl>
@@ -1,33 +1,72 @@
using System.Collections.ObjectModel;
using System;
using System.Collections.ObjectModel;
using System.Reactive.Disposables.Fluent;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using DynamicData;
using DynamicData.Binding;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Section;
public class ConfigurationSectionDesignViewModel : ActivatableViewModelBase
public partial class ConfigurationSectionDesignViewModel : ActivatableViewModelBase
{
public ConfigurationSection ConfigurationSection { get; }
public ObservableCollection<ActivatableViewModelBase> Items { get; }
private readonly IWindowService _windowService;
[Notify] private ReadOnlyObservableCollection<ConfigurationItemDesignViewModel>? _items;
public ConfigurationSectionDesignViewModel(ConfigurationSection configurationSection)
public ConfigurationSectionDesignViewModel(ConfigurationSection configurationSection, IWindowService windowService)
{
_windowService = windowService;
ConfigurationSection = configurationSection;
Items = [];
foreach (IConfigurationItem item in ConfigurationSection.Items)
this.WhenActivated(d =>
{
if (item is ConfigurationTextItem textItem)
Items.Add(new ConfigurationTextItemDesignViewModel(textItem));
else if (item is ConfigurationStringItem stringItem)
Items.Add(new ConfigurationStringItemDesignViewModel(stringItem));
else if (item is ConfigurationBooleanItem booleanItem)
Items.Add(new ConfigurationBooleanItemDesignViewModel(booleanItem));
else if (item is ConfigurationNumericItem numberItem)
Items.Add(new ConfigurationNumericItemDesignViewModel(numberItem));
else if (item is ConfigurationSKColorItem colorItem)
Items.Add(new ConfigurationSKColorItemDesignViewModel(colorItem));
else if (item is ConfigurationColorGradientItem colorGradientItem)
Items.Add(new ConfigurationColorGradientItemDesignViewModel(colorGradientItem));
}
ConfigurationSection.Items
.ToObservableChangeSet()
.Transform(CreateViewModelForItem)
.Bind(out ReadOnlyObservableCollection<ConfigurationItemDesignViewModel> items)
.Subscribe()
.DisposeWith(d);
Items = items;
});
}
public ConfigurationSection ConfigurationSection { get; }
public async Task RemoveSection()
{
ConfigurationSection.ProfileConfiguration.ConfigurationSections.Remove(ConfigurationSection);
}
public async Task AddItem()
{
await _windowService.CreateContentDialog()
.WithTitle("Add Item")
.WithViewModel(out AddConfigurationItemDesignViewModel _, ConfigurationSection)
.ShowAsync();
}
public void RemoveItem(ConfigurationItemDesignViewModel viewModel)
{
ConfigurationSection.Items.Remove(viewModel.Item);
}
private ConfigurationItemDesignViewModel CreateViewModelForItem(IConfigurationItem item)
{
return item switch
{
ConfigurationTextItem textItem => new ConfigurationTextItemDesignViewModel(textItem, ConfigurationSection),
ConfigurationStringItem stringItem => new ConfigurationStringItemDesignViewModel(stringItem, ConfigurationSection),
ConfigurationBooleanItem booleanItem => new ConfigurationBooleanItemDesignViewModel(booleanItem, ConfigurationSection),
ConfigurationNumericItem numberItem => new ConfigurationNumericItemDesignViewModel(numberItem, ConfigurationSection),
ConfigurationSKColorItem colorItem => new ConfigurationSKColorItemDesignViewModel(colorItem, ConfigurationSection),
ConfigurationColorGradientItem colorGradientItem => new ConfigurationColorGradientItemDesignViewModel(colorGradientItem, ConfigurationSection),
_ => throw new ArgumentException($"Unknown configuration item type: {item.GetType()}")
};
}
}
@@ -3,12 +3,27 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.ProfileEditor"
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.DesignProfileView"
x:DataType="profileEditor:DesignProfileViewModel">
<Border Classes="router-container">
<TextBlock>Design</TextBlock>
<Border Classes="router-container" Padding="8">
<Grid RowDefinitions="*" ColumnDefinitions="0.6*, Auto" ColumnSpacing="8" RowSpacing="8">
<ContentControl Grid.Column="0" Grid.Row="0" Content="{CompiledBinding PreviewViewModel}" />
<ScrollViewer Grid.Column="1" Grid.Row="0">
<StackPanel>
<ItemsControl ItemsSource="{CompiledBinding Sections}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button HorizontalAlignment="Stretch" Margin="0 8 0 0" ToolTip.Tip="Add Section" Command="{CompiledBinding AddSection}">
<avalonia:MaterialIcon Kind="Add" />
</Button>
</StackPanel>
</ScrollViewer>
</Grid>
</Border>
</UserControl>
@@ -1,65 +1,87 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables.Fluent;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Screens.Workshop.Library.Tabs;
using Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Preview;
using Artemis.UI.Screens.ProfileEditor.DesignPanels.Section;
using Artemis.UI.Shared.Routing;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Services;
using Artemis.UI.Shared.Services.ProfileEditor;
using DynamicData;
using DynamicData.Binding;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor;
public partial class DesignProfileViewModel : RoutableScreen<ProfileViewModelParameters>
{
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileService _profileService;
private readonly IWorkshopService _workshopService;
private readonly IRouter _router;
private readonly Func<InstalledEntry, InstalledTabItemViewModel> _getInstalledTabItemViewModel;
[Notify] private ProfileConfiguration? _profileConfiguration;
[Notify] private InstalledEntry? _workshopEntry;
[Notify] private InstalledTabItemViewModel? _entryViewModel;
[Notify] private ReadOnlyObservableCollection<ConfigurationSectionDesignViewModel>? _sections;
public DesignProfileViewModel(IProfileService profileService, IWorkshopService workshopService, IRouter router, Func<InstalledEntry, InstalledTabItemViewModel> getInstalledTabItemViewModel)
public DesignProfileViewModel(IProfileService profileService, IProfileEditorService profileEditorService, PreviewViewModel previewViewModel,
Func<ConfigurationSection, ConfigurationSectionDesignViewModel> getConfigurationSectionDesignViewModel)
{
_profileService = profileService;
_workshopService = workshopService;
_router = router;
_getInstalledTabItemViewModel = getInstalledTabItemViewModel;
_profileEditorService = profileEditorService;
ParameterSource = ParameterSource.Route;
PreviewViewModel = previewViewModel;
this.WhenActivated(d =>
{
this.WhenAnyValue(vm => vm.ProfileConfiguration)
.Select(p => p?.ConfigurationSections.ToObservableChangeSet() ?? Observable.Empty<IChangeSet<ConfigurationSection>>())
.Switch()
.Transform(getConfigurationSectionDesignViewModel)
.Bind(out ReadOnlyObservableCollection<ConfigurationSectionDesignViewModel> sections)
.Subscribe()
.DisposeWith(d);
Sections = sections;
});
}
public async Task DisableAutoUpdate()
{
if (WorkshopEntry != null)
{
_workshopService.SetAutoUpdate(WorkshopEntry, false);
}
public PreviewViewModel PreviewViewModel { get; }
if (ProfileConfiguration != null)
{
await _router.Navigate($"profile/{ProfileConfiguration.ProfileId}/editor");
}
}
public override Task OnNavigating(ProfileViewModelParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
/// <inheritdoc />
public override async Task OnNavigating(ProfileViewModelParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
ProfileConfiguration = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
ProfileConfiguration? profileConfiguration = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
// If the profile doesn't exist, cancel navigation
if (ProfileConfiguration == null)
if (profileConfiguration == null)
{
args.Cancel();
return Task.CompletedTask;
return;
}
WorkshopEntry = _workshopService.GetInstalledEntryByProfile(ProfileConfiguration);
EntryViewModel = WorkshopEntry != null ? _getInstalledTabItemViewModel(WorkshopEntry) : null;
if (EntryViewModel != null)
EntryViewModel.DisplayManagement = false;
return Task.CompletedTask;
await _profileEditorService.ChangeCurrentProfileConfiguration(profileConfiguration);
ProfileConfiguration = profileConfiguration;
}
/// <inheritdoc />
public override async Task OnClosing(NavigationArguments args)
{
if (!args.Path.StartsWith("profile"))
{
ProfileConfiguration = null;
await _profileEditorService.ChangeCurrentProfileConfiguration(null);
}
}
public async Task AddSection()
{
ProfileConfiguration?.ConfigurationSections.Add(new ConfigurationSection(ProfileConfiguration)
{
Name = $"New Section {ProfileConfiguration.ConfigurationSections.Count(s => s.Name.StartsWith("New Section")) + 1}"
});
}
}