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
+748 -223

No files matched your search

@@ -8,18 +8,18 @@ public class ConfigurationBooleanItem : ConfigurationInputItem<bool>
/// <summary> /// <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> /// </summary>
public required string TrueText public string TrueText
{ {
get; get;
set => SetAndNotify(ref field, value); set => SetAndNotify(ref field, value);
} } = "Yes";
/// <summary> /// <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> /// </summary>
public required string FalseText public string FalseText
{ {
get; get;
set => SetAndNotify(ref field, value); set => SetAndNotify(ref field, value);
} } = "No";
} }
@@ -35,6 +35,15 @@ public class ConfigurationInputItem<T> : CorePropertyChanged, IConfigurationItem
set => SetAndNotify(ref field, value); set => SetAndNotify(ref field, value);
} }
/// <summary>
/// Gets or sets the default value of the configuration item.
/// </summary>
public T? DefaultValue
{
get;
set => SetAndNotify(ref field, value);
}
/// <summary> /// <summary>
/// Gets or sets the collection of dropdown values for this configuration item. /// 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. /// When populated, the configuration item will be rendered as a dropdown/combo box.
@@ -5,7 +5,21 @@
/// </summary> /// </summary>
public class ConfigurationNumericItem : ConfigurationInputItem<Numeric> public class ConfigurationNumericItem : ConfigurationInputItem<Numeric>
{ {
public Numeric? Minimum { get; set; } public Numeric? Minimum
public Numeric? Maximum { get; set; } {
public bool Slider { get; set; } get;
set => SetAndNotify(ref field, value);
}
public Numeric? Maximum
{
get;
set => SetAndNotify(ref field, value);
}
public bool Slider
{
get;
set => SetAndNotify(ref field, value);
}
} }
@@ -7,6 +7,20 @@ namespace Artemis.Core;
/// </summary> /// </summary>
public class ConfigurationSection : CorePropertyChanged public class ConfigurationSection : CorePropertyChanged
{ {
/// <summary>
/// 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> /// <summary>
/// Gets or sets the name of the configuration section. /// Gets or sets the name of the configuration section.
/// </summary> /// </summary>
@@ -156,7 +156,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
} }
/// <summary> /// <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> /// </summary>
public bool IsConfigurable public bool IsConfigurable
{ {
@@ -251,19 +251,6 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
return $"[ProfileConfiguration] {nameof(Name)}: {Name}"; 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) internal void LoadModules(List<Module> enabledModules)
{ {
if (_disposed) if (_disposed)
@@ -280,6 +267,19 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
ActivationCondition.Dispose(); 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 #region Implementation of IStorageModel
/// <inheritdoc /> /// <inheritdoc />
@@ -305,27 +305,27 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
// Placeholder configuration sections // Placeholder configuration sections
ConfigurationSections.Clear(); 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 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 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[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[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 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 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 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 ConfigurationColorGradientItem {Name = "Color gradient"});
ConfigurationSections[2].Items.Add(new ConfigurationSKColorItem() {Name = "A simple color", Description = "Again with a description"}); ConfigurationSections[2].Items.Add(new ConfigurationSKColorItem {Name = "A simple color", Description = "Again with a description"});
} }
/// <inheritdoc /> /// <inheritdoc />
+11 -8
View File
@@ -51,6 +51,9 @@
</Design.PreviewWith> </Design.PreviewWith>
<!-- Styles --> <!-- Styles -->
<Style Selector=":is(Button).icon-button-outlined">
<Setter Property="Padding" Value="7" />
</Style>
<Style Selector=":is(Button).icon-button"> <Style Selector=":is(Button).icon-button">
<Setter Property="BorderBrush" Value="Transparent" /> <Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
@@ -97,19 +100,19 @@
</Style> </Style>
<Style Selector="Button.title-bar-button"> <Style Selector="Button.title-bar-button">
<Setter Property="Width" Value="46"></Setter> <Setter Property="Width" Value="46" />
<Setter Property="Height" Value="30"></Setter> <Setter Property="Height" Value="30" />
<Setter Property="BorderThickness" Value="0"></Setter> <Setter Property="BorderThickness" Value="0" />
<Setter Property="CornerRadius" Value="0"></Setter> <Setter Property="CornerRadius" Value="0" />
<Setter Property="Margin" Value="0"></Setter> <Setter Property="Margin" Value="0" />
<Setter Property="Background" Value="Transparent"></Setter> <Setter Property="Background" Value="Transparent" />
</Style> </Style>
<Style Selector="Button.title-bar-button:pointerover"> <Style Selector="Button.title-bar-button:pointerover">
<Setter Property="Background" Value="Red"></Setter> <Setter Property="Background" Value="Red" />
</Style> </Style>
<Style Selector="Button.danger"> <Style Selector="Button.danger">
<Setter Property="Background" Value="#D64848"></Setter> <Setter Property="Background" Value="#D64848" />
</Style> </Style>
<!-- <Style Selector="Button.danger:pointerover"> --> <!-- <Style Selector="Button.danger:pointerover"> -->
@@ -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: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: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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationTextItemDesignDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.ConfigurationPanels.Items.ConfigurationTextItemView"
x:DataType="items:ConfigurationTextItemDesignViewModel"> x:DataType="items:ConfigurationTextItemViewModel">
<TextBox Text="{CompiledBinding Item.Text}" /> <TextBlock Text="{CompiledBinding Item.Text}" />
</UserControl> </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: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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationBooleanItemDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationBooleanItemDesignView"
x:DataType="items:ConfigurationBooleanItemDesignViewModel"> x:DataType="items:ConfigurationBooleanItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" /> <TextBox Text="{CompiledBinding BooleanItem.Name}" Watermark="Name" />
<TextBlock Classes="subtitle" <TextBox Text="{CompiledBinding BooleanItem.Description}" Watermark="Description" />
TextWrapping="Wrap" <Grid ColumnDefinitions="*,*" ColumnSpacing="5">
Text="{CompiledBinding Item.Description}" <TextBox Grid.Column="0" Text="{CompiledBinding BooleanItem.TrueText}" Watermark="Enabled label" />
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" /> <TextBox Grid.Column="1" Text="{CompiledBinding BooleanItem.FalseText}" Watermark="Disabled label" />
</Grid>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1">
<ToggleSwitch IsChecked="{CompiledBinding Item.Value}" <TextBlock Margin="0 14 0 4">Default:</TextBlock>
OnContent="{CompiledBinding Item.TrueText}" <ToggleSwitch IsChecked="{CompiledBinding BooleanItem.Value}"
OffContent="{CompiledBinding Item.FalseText}" OnContent="{CompiledBinding BooleanItem.TrueText}"
MinWidth="0" OffContent="{CompiledBinding BooleanItem.FalseText}"
Margin="0 -10" Width="150"
FlowDirection="RightToLeft"/> Margin="0 -6 0 0"
HorizontalAlignment="Left" />
</StackPanel> </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> </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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; 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 ConfigurationBooleanItem BooleanItem { get; } = item;
public ConfigurationBooleanItemDesignViewModel(ConfigurationBooleanItem item)
{
Item = item;
}
} }
@@ -4,21 +4,23 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared" xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationColorGradientItemDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationColorGradientItemDesignView"
x:DataType="items:ConfigurationColorGradientItemDesignViewModel"> x:DataType="items:ConfigurationColorGradientItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" /> <TextBox Text="{CompiledBinding GradientItem.Name}" Watermark="Name" />
<TextBlock Classes="subtitle" <TextBox Text="{CompiledBinding GradientItem.Description}" Watermark="Description" />
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<gradientPicker:GradientPickerButton Width="150" <gradientPicker:GradientPickerButton Width="150"
ColorGradient="{CompiledBinding Item.Value}" ColorGradient="{CompiledBinding GradientItem.Value}"
VerticalAlignment="Center"/> VerticalAlignment="Center" />
</StackPanel> </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> </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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,17 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; 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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared" xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationNumericItemDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationNumericItemDesignView"
x:DataType="items:ConfigurationNumericItemDesignViewModel"> x:DataType="items:ConfigurationNumericItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" /> <TextBox Text="{CompiledBinding NumericItem.Name}" Watermark="Name" />
<TextBlock Classes="subtitle" <TextBox Text="{CompiledBinding NumericItem.Description}" Watermark="Description" />
TextWrapping="Wrap" <ToggleSwitch IsChecked="{CompiledBinding NumericItem.Slider}"
Text="{CompiledBinding Item.Description}" OnContent="Slider"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" /> OffContent="Number box"
MinWidth="0"
Margin="0 -8" />
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Top">
<controls:NumberBox Width="150" IsVisible="{CompiledBinding !Item.Slider}"> <TextBlock Margin="0 14 0 4">Default:</TextBlock>
<controls:NumberBox Width="150" IsVisible="{CompiledBinding !NumericItem.Slider}">
<Interaction.Behaviors> <Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding Item.Value}" /> <behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding NumericItem.Value}" />
</Interaction.Behaviors> </Interaction.Behaviors>
</controls:NumberBox> </controls:NumberBox>
<Slider Minimum="{CompiledBinding Item.Minimum}" <Slider Minimum="{CompiledBinding NumericItem.Minimum}"
Maximum="{CompiledBinding Item.Maximum}" Maximum="{CompiledBinding NumericItem.Maximum}"
Width="150" Width="150"
IsVisible="{CompiledBinding Item.Slider}" Margin="0 -5 0 0"
Value="{CompiledBinding Item.Value, Mode=TwoWay}" /> IsVisible="{CompiledBinding NumericItem.Slider}"
Value="{CompiledBinding NumericItem.Value, Mode=TwoWay}" />
</StackPanel> </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> </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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; 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 ConfigurationNumericItem NumericItem { get; } = item;
public ConfigurationNumericItemDesignViewModel(ConfigurationNumericItem item)
{
Item = item;
}
} }
@@ -4,22 +4,25 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationSKColorItemDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationSKColorItemDesignView"
x:DataType="items:ConfigurationSKColorItemDesignViewModel"> x:DataType="items:ConfigurationSKColorItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" /> <TextBox Text="{CompiledBinding ColorItem.Name}" Watermark="Name" />
<TextBlock Classes="subtitle" <TextBox Text="{CompiledBinding ColorItem.Description}" Watermark="Description" />
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBlock Margin="0 14 0 4">Default:</TextBlock>
<controls:ColorPickerButton Color="{CompiledBinding Item.Value, Converter={StaticResource SKColorToColorConverter}}" <controls:ColorPickerButton Color="{CompiledBinding ColorItem.Value, Converter={StaticResource SKColorToColorConverter}}"
Width="150"
ShowAcceptDismissButtons="False" ShowAcceptDismissButtons="False"
FlyoutPlacement="Right" /> FlyoutPlacement="Right" />
</StackPanel> </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> </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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; 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) public ConfigurationSKColorItem ColorItem { get; } = item;
{
Item = item;
}
public ConfigurationSKColorItem Item { get; }
} }
@@ -3,19 +3,22 @@
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:items="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Items" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationStringItemDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Items.ConfigurationStringItemDesignView"
x:DataType="items:ConfigurationStringItemDesignViewModel"> x:DataType="items:ConfigurationStringItemDesignViewModel">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto" ColumnSpacing="5">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="5">
<TextBlock Text="{CompiledBinding Item.Name}" TextWrapping="Wrap" /> <TextBox Text="{CompiledBinding StringItem.Name}" Watermark="Name" />
<TextBlock Classes="subtitle" <TextBox Text="{CompiledBinding StringItem.Description}" Watermark="Description" />
TextWrapping="Wrap"
Text="{CompiledBinding Item.Description}"
IsVisible="{CompiledBinding Item.Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <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> </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> </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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
@@ -1,14 +1,8 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; 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 ConfigurationStringItem StringItem { get; } = item;
public ConfigurationStringItemDesignViewModel(ConfigurationStringItem item)
{
Item = 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; 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; 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: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:section="clr-namespace:Artemis.UI.Screens.ProfileEditor.DesignPanels.Section" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Section.ConfigurationSectionDesignView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignPanels.Section.ConfigurationSectionDesignView"
x:DataType="section:ConfigurationSectionDesignViewModel"> x:DataType="section:ConfigurationSectionDesignViewModel">
<Border Classes="card" VerticalAlignment="Top"> <Border Classes="card" VerticalAlignment="Top">
<StackPanel> <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" /> <Border Classes="card-separator" />
<ItemsControl ItemsSource="{CompiledBinding Items}"> <ItemsControl ItemsSource="{CompiledBinding Items}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Classes="device-view-model-container"> <StackPanel Classes="device-view-model-container">
<!-- Your existing item template goes here --> <ContentControl Content="{CompiledBinding}" />
<ContentControl Content="{CompiledBinding}"/>
<Border Classes="card-separator" Name="Separator" /> <Border Classes="card-separator" Name="Separator" />
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
@@ -29,6 +34,10 @@
</Styles> </Styles>
</ItemsControl.Styles> </ItemsControl.Styles>
</ItemsControl> </ItemsControl>
<Button HorizontalAlignment="Stretch" Margin="0 8 0 0" ToolTip.Tip="Add item" Command="{CompiledBinding AddItem}">
<avalonia:MaterialIcon Kind="Add" />
</Button>
</StackPanel> </StackPanel>
</Border> </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.Core;
using Artemis.UI.Screens.ProfileEditor.DesignPanels.Items; using Artemis.UI.Screens.ProfileEditor.DesignPanels.Items;
using Artemis.UI.Shared; 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; namespace Artemis.UI.Screens.ProfileEditor.DesignPanels.Section;
public class ConfigurationSectionDesignViewModel : ActivatableViewModelBase public partial class ConfigurationSectionDesignViewModel : ActivatableViewModelBase
{ {
public ConfigurationSection ConfigurationSection { get; } private readonly IWindowService _windowService;
public ObservableCollection<ActivatableViewModelBase> Items { get; } [Notify] private ReadOnlyObservableCollection<ConfigurationItemDesignViewModel>? _items;
public ConfigurationSectionDesignViewModel(ConfigurationSection configurationSection) public ConfigurationSectionDesignViewModel(ConfigurationSection configurationSection, IWindowService windowService)
{ {
_windowService = windowService;
ConfigurationSection = configurationSection; ConfigurationSection = configurationSection;
Items = [];
foreach (IConfigurationItem item in ConfigurationSection.Items) this.WhenActivated(d =>
{ {
if (item is ConfigurationTextItem textItem) ConfigurationSection.Items
Items.Add(new ConfigurationTextItemDesignViewModel(textItem)); .ToObservableChangeSet()
else if (item is ConfigurationStringItem stringItem) .Transform(CreateViewModelForItem)
Items.Add(new ConfigurationStringItemDesignViewModel(stringItem)); .Bind(out ReadOnlyObservableCollection<ConfigurationItemDesignViewModel> items)
else if (item is ConfigurationBooleanItem booleanItem) .Subscribe()
Items.Add(new ConfigurationBooleanItemDesignViewModel(booleanItem)); .DisposeWith(d);
else if (item is ConfigurationNumericItem numberItem)
Items.Add(new ConfigurationNumericItemDesignViewModel(numberItem)); Items = items;
else if (item is ConfigurationSKColorItem colorItem) });
Items.Add(new ConfigurationSKColorItemDesignViewModel(colorItem));
else if (item is ConfigurationColorGradientItem colorGradientItem)
Items.Add(new ConfigurationColorGradientItemDesignViewModel(colorGradientItem));
} }
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: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:profileEditor="clr-namespace:Artemis.UI.Screens.ProfileEditor" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DesignProfileView" x:Class="Artemis.UI.Screens.ProfileEditor.DesignProfileView"
x:DataType="profileEditor:DesignProfileViewModel"> x:DataType="profileEditor:DesignProfileViewModel">
<Border Classes="router-container"> <Border Classes="router-container" Padding="8">
<Grid RowDefinitions="*" ColumnDefinitions="0.6*, Auto" ColumnSpacing="8" RowSpacing="8">
<TextBlock>Design</TextBlock> <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> </Border>
</UserControl> </UserControl>
@@ -1,65 +1,87 @@
using System; using System;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reactive.Disposables.Fluent;
using System.Reactive.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; 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.UI.Shared.Routing;
using Artemis.WebClient.Workshop.Models; using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.WebClient.Workshop.Services; using DynamicData;
using DynamicData.Binding;
using PropertyChanged.SourceGenerator; using PropertyChanged.SourceGenerator;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor; namespace Artemis.UI.Screens.ProfileEditor;
public partial class DesignProfileViewModel : RoutableScreen<ProfileViewModelParameters> public partial class DesignProfileViewModel : RoutableScreen<ProfileViewModelParameters>
{ {
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
private readonly IWorkshopService _workshopService;
private readonly IRouter _router;
private readonly Func<InstalledEntry, InstalledTabItemViewModel> _getInstalledTabItemViewModel;
[Notify] private ProfileConfiguration? _profileConfiguration; [Notify] private ProfileConfiguration? _profileConfiguration;
[Notify] private InstalledEntry? _workshopEntry; [Notify] private ReadOnlyObservableCollection<ConfigurationSectionDesignViewModel>? _sections;
[Notify] private InstalledTabItemViewModel? _entryViewModel;
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; _profileService = profileService;
_workshopService = workshopService; _profileEditorService = profileEditorService;
_router = router;
_getInstalledTabItemViewModel = getInstalledTabItemViewModel;
ParameterSource = ParameterSource.Route; 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() public PreviewViewModel PreviewViewModel { get; }
{
if (WorkshopEntry != null)
{
_workshopService.SetAutoUpdate(WorkshopEntry, false);
}
if (ProfileConfiguration != null) /// <inheritdoc />
public override async Task OnNavigating(ProfileViewModelParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{ {
await _router.Navigate($"profile/{ProfileConfiguration.ProfileId}/editor"); ProfileConfiguration? profileConfiguration = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
}
}
public override Task OnNavigating(ProfileViewModelParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
ProfileConfiguration = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
// If the profile doesn't exist, cancel navigation // If the profile doesn't exist, cancel navigation
if (ProfileConfiguration == null) if (profileConfiguration == null)
{ {
args.Cancel(); args.Cancel();
return Task.CompletedTask; return;
} }
WorkshopEntry = _workshopService.GetInstalledEntryByProfile(ProfileConfiguration); await _profileEditorService.ChangeCurrentProfileConfiguration(profileConfiguration);
EntryViewModel = WorkshopEntry != null ? _getInstalledTabItemViewModel(WorkshopEntry) : null; ProfileConfiguration = profileConfiguration;
if (EntryViewModel != null) }
EntryViewModel.DisplayManagement = false;
return Task.CompletedTask; /// <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}"
});
} }
} }