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

Gradient editor - WIP commit

This commit is contained in:
Robert 2020-03-13 23:45:25 +01:00
parent d96c8a1879
commit d0fbd63592
21 changed files with 315 additions and 322 deletions

View File

@ -40,7 +40,7 @@
<ItemGroup>
<PackageReference Include="Ben.Demystifier" Version="0.1.6" />
<PackageReference Include="Castle.Core" Version="4.4.0" />
<PackageReference Include="LiteDB" Version="5.0.3" />
<PackageReference Include="LiteDB" Version="5.0.4" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Ninject" Version="3.3.4" />

View File

@ -12,20 +12,20 @@ namespace Artemis.Core.Models.Profile
{
public ColorGradient()
{
Colors = new BindableCollection<ColorGradientColor>();
Stops = new BindableCollection<ColorGradientStop>();
}
public BindableCollection<ColorGradientColor> Colors { get; }
public BindableCollection<ColorGradientStop> Stops { get; }
public float Rotation { get; set; }
public SKColor[] GetColorsArray()
{
return Colors.OrderBy(c => c.Position).Select(c => c.Color).ToArray();
return Stops.OrderBy(c => c.Position).Select(c => c.Color).ToArray();
}
public float[] GetColorPositionsArray()
public float[] GetPositionsArray()
{
return Colors.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
}
#region PropertyChanged
@ -42,18 +42,18 @@ namespace Artemis.Core.Models.Profile
public void OnColorValuesUpdated()
{
OnPropertyChanged(nameof(Colors));
OnPropertyChanged(nameof(Stops));
}
public SKColor GetColor(float position)
{
var point = Colors.SingleOrDefault(f => f.Position == position);
var point = Stops.SingleOrDefault(f => f.Position == position);
if (point != null) return point.Color;
var before = Colors.First(w => w.Position == Colors.Min(m => m.Position));
var after = Colors.First(w => w.Position == Colors.Max(m => m.Position));
var before = Stops.First(w => w.Position == Stops.Min(m => m.Position));
var after = Stops.First(w => w.Position == Stops.Max(m => m.Position));
foreach (var gs in Colors)
foreach (var gs in Stops)
{
if (gs.Position < position && gs.Position > before.Position)
before = gs;
@ -71,9 +71,9 @@ namespace Artemis.Core.Models.Profile
}
}
public class ColorGradientColor : INotifyPropertyChanged
public class ColorGradientStop : INotifyPropertyChanged
{
public ColorGradientColor(SKColor color, float position)
public ColorGradientStop(SKColor color, float position)
{
Color = color;
Position = position;

View File

@ -5,6 +5,6 @@
<LangVersion>7</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LiteDB" Version="5.0.3" />
<PackageReference Include="LiteDB" Version="5.0.4" />
</ItemGroup>
</Project>

View File

@ -24,6 +24,7 @@
<PackageReference Include="MaterialDesignExtensions" Version="3.0.0" />
<PackageReference Include="MaterialDesignThemes" Version="3.0.1" />
<PackageReference Include="Ninject" Version="3.3.4" />
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
<PackageReference Include="SkiaSharp" Version="1.68.2-preview.29" />
<PackageReference Include="Stylet" Version="1.3.1" />
<PackageReference Include="System.Buffers" Version="4.5.0" />

View File

@ -14,12 +14,12 @@ namespace Artemis.UI.Shared.Converters
/// Converts <see cref="T:Artemis.Core.Models.Profile.ColorGradient" /> into a
/// <see cref="T:System.Windows.Media.GradientStopCollection" />.
/// </summary>
[ValueConversion(typeof(BindableCollection<ColorGradientColor>), typeof(GradientStopCollection))]
[ValueConversion(typeof(BindableCollection<ColorGradientStop>), typeof(GradientStopCollection))]
public class ColorGradientToGradientStopsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var colorGradients = (BindableCollection<ColorGradientColor>) value;
var colorGradients = (BindableCollection<ColorGradientStop>) value;
var collection = new GradientStopCollection();
if (colorGradients == null)
return collection;
@ -32,12 +32,12 @@ namespace Artemis.UI.Shared.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var collection = (GradientStopCollection) value;
var colorGradients = new BindableCollection<ColorGradientColor>();
var colorGradients = new BindableCollection<ColorGradientStop>();
if (collection == null)
return colorGradients;
foreach (var c in collection.OrderBy(s => s.Offset))
colorGradients.Add(new ColorGradientColor(new SKColor(c.Color.R, c.Color.G, c.Color.B, c.Color.A), (float) c.Offset));
colorGradients.Add(new ColorGradientStop(new SKColor(c.Color.R, c.Color.G, c.Color.B, c.Color.A), (float) c.Offset));
return colorGradients;
}
}

View File

@ -43,7 +43,7 @@
<Ellipse Stroke="{DynamicResource NormalBorderBrush}" Cursor="Hand" MouseUp="UIElement_OnMouseUp">
<Ellipse.Fill>
<LinearGradientBrush
GradientStops="{Binding ColorGradient.Colors, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource ColorGradientToGradientStopsConverter}}" />
GradientStops="{Binding ColorGradient.Stops, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource ColorGradientToGradientStopsConverter}}" />
</Ellipse.Fill>
</Ellipse>
</Border>

View File

@ -6,7 +6,6 @@ using System.Windows.Controls;
using System.Windows.Input;
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Annotations;
using Artemis.UI.Shared.Screens.GradientEditor;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared
@ -16,6 +15,14 @@ namespace Artemis.UI.Shared
/// </summary>
public partial class GradientPicker : UserControl, INotifyPropertyChanged
{
private static IGradientPickerService _gradientPickerService;
private bool _inCallback;
public GradientPicker()
{
InitializeComponent();
}
/// <summary>
/// Used by the gradient picker to load saved gradients, do not touch or it'll just throw an exception
/// </summary>
@ -30,25 +37,9 @@ namespace Artemis.UI.Shared
}
}
public static readonly DependencyProperty ColorGradientProperty = DependencyProperty.Register(nameof(ColorGradient), typeof(ColorGradient), typeof(GradientPicker),
new FrameworkPropertyMetadata(default(ColorGradient), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, ColorGradientPropertyChangedCallback));
public static readonly RoutedEvent ColorGradientChangedEvent =
EventManager.RegisterRoutedEvent(
nameof(ColorGradient),
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<ColorGradient>),
typeof(GradientPicker));
private static IGradientPickerService _gradientPickerService;
private bool _inCallback;
public GradientPicker()
{
InitializeComponent();
}
/// <summary>
/// Gets or sets the currently selected color gradient
/// </summary>
public ColorGradient ColorGradient
{
get => (ColorGradient) GetValue(ColorGradientProperty);
@ -76,8 +67,17 @@ namespace Artemis.UI.Shared
private void UIElement_OnMouseUp(object sender, MouseButtonEventArgs e)
{
var gradientEditor = new GradientEditor(ColorGradient);
gradientEditor.ShowDialog();
GradientPickerService.ShowGradientPicker(ColorGradient);
}
#region Static WPF fields
public static readonly DependencyProperty ColorGradientProperty = DependencyProperty.Register(nameof(ColorGradient), typeof(ColorGradient), typeof(GradientPicker),
new FrameworkPropertyMetadata(default(ColorGradient), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, ColorGradientPropertyChangedCallback));
public static readonly RoutedEvent ColorGradientChangedEvent =
EventManager.RegisterRoutedEvent(nameof(ColorGradient), RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<ColorGradient>), typeof(GradientPicker));
#endregion
}
}

View File

@ -0,0 +1,14 @@
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Screens.GradientEditor;
namespace Artemis.UI.Shared.Ninject.Factories
{
public interface IVmFactory
{
}
public interface IGradientEditorVmFactory : IVmFactory
{
GradientEditorViewModel Create(ColorGradient colorGradient);
}
}

View File

@ -0,0 +1,37 @@
using System;
using Artemis.UI.Shared.Ninject.Factories;
using Artemis.UI.Shared.Services.Interfaces;
using Ninject.Extensions.Conventions;
using Ninject.Modules;
namespace Artemis.UI.Shared.Ninject
{
// ReSharper disable once InconsistentNaming
public class SharedUIModule : NinjectModule
{
public override void Load()
{
if (Kernel == null)
throw new ArgumentNullException("Kernel shouldn't be null here.");
// Bind UI factories
Kernel.Bind(x =>
{
x.FromAssemblyContaining<IVmFactory>()
.SelectAllInterfaces()
.InheritedFrom<IVmFactory>()
.BindToFactory();
});
// Bind all shared UI services as singletons
Kernel.Bind(x =>
{
x.FromAssemblyContaining<IArtemisSharedUIService>()
.SelectAllClasses()
.InheritedFrom<IArtemisSharedUIService>()
.BindAllInterfaces()
.Configure(c => c.InSingletonScope());
});
}
}
}

View File

@ -0,0 +1,34 @@
<UserControl x:Class="Artemis.UI.Shared.Screens.GradientEditor.ColorStopView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Shared.Screens.GradientEditor"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:ColorStopViewModel}">
<UserControl.Resources>
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
</UserControl.Resources>
<Path Data="M13.437011,33.065002 C9.7268463,29.334181 7.812011,26.379009 4.874511,23.379009 1.687011,19.566509 0.12600673,17.206803 5.6843419E-14,14.127608 0.062010996,2.0027046 11.158781,-0.062991121 13.43702,0.0014351187 M13.438011,33.065016 C17.148173,29.334199 19.063008,26.379023 22.00051,23.379017 25.188007,19.566519 26.749013,17.206806 26.875018,14.127613 26.813007,2.002704 15.716239,-0.062987381 13.438,0.0014388781"
Stroke="{DynamicResource NormalBorderBrush}"
StrokeThickness="2"
Cursor="Hand"
MouseDown="{s:Action StopMouseDown}"
MouseUp="{s:Action StopMouseUp}"
MouseMove="{s:Action StopMouseMove}"
Fill="{Binding Path=Color, Converter={StaticResource SKColorToColorConverter}}">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="180" />
<TranslateTransform X="14" Y="33" />
<ScaleTransform ScaleX="0.45" ScaleY="0.5" />
</TransformGroup>
</Path.RenderTransform>
<Path.Effect>
<DropShadowEffect BlurRadius="15" Opacity="0.25" Direction="180" />
</Path.Effect>
</Path>
</UserControl>

View File

@ -0,0 +1,80 @@
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Artemis.Core.Models.Profile;
using PropertyChanged;
using SkiaSharp;
using Stylet;
namespace Artemis.UI.Shared.Screens.GradientEditor
{
public class ColorStopViewModel : PropertyChangedBase
{
private readonly GradientEditorViewModel _gradientEditorViewModel;
public ColorStopViewModel(GradientEditorViewModel gradientEditorViewModel)
{
_gradientEditorViewModel = gradientEditorViewModel;
}
public ColorGradientStop ColorStop { get; set; }
public double Offset => ColorStop.Position * _gradientEditorViewModel.PreviewWidth;
public SKColor Color => ColorStop.Color;
#region Movement
private double _mouseDownOffset;
private DateTime _mouseDownTime;
public void StopMouseDown(object sender, MouseButtonEventArgs e)
{
var position = GetPositionInPreview(sender, e);
((IInputElement) sender).CaptureMouse();
_mouseDownOffset = Offset - position.X;
_mouseDownTime = DateTime.Now;
}
public void StopMouseUp(object sender, MouseButtonEventArgs e)
{
// On regular click, select this color stop
if (DateTime.Now - _mouseDownTime <= TimeSpan.FromMilliseconds(250))
{
}
((IInputElement) sender).ReleaseMouseCapture();
e.Handled = true;
}
public void StopMouseMove(object sender, MouseEventArgs e)
{
if (!((IInputElement) sender).IsMouseCaptured)
return;
var position = GetPositionInPreview(sender, e);
// Scale down with a precision of 3 decimals
var newPosition = Math.Round((position.X + _mouseDownOffset) / _gradientEditorViewModel.PreviewWidth, 3, MidpointRounding.AwayFromZero);
// Limit from 0.0 to 1.0
newPosition = Math.Min(1, Math.Max(0, newPosition));
ColorStop.Position = (float) newPosition;
NotifyOfPropertyChange(() => Offset);
NotifyOfPropertyChange(() => Color);
}
private Point GetPositionInPreview(object sender, MouseEventArgs e)
{
var parent = VisualTreeHelper.GetParent((DependencyObject) sender);
return e.GetPosition((IInputElement) parent);
}
#endregion
public void Update(ColorGradientStop colorStop)
{
ColorStop = colorStop;
NotifyOfPropertyChange(() => Offset);
NotifyOfPropertyChange(() => Color);
}
}
}

View File

@ -1,70 +0,0 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Annotations;
using MaterialDesignExtensions.Controls;
namespace Artemis.UI.Shared.Screens.GradientEditor
{
/// <summary>
/// Interaction logic for GradientEditor.xaml
/// </summary>
public partial class GradientEditor : MaterialWindow, INotifyPropertyChanged
{
public static readonly DependencyProperty ColorGradientProperty = DependencyProperty.Register(nameof(ColorGradient), typeof(ColorGradient), typeof(GradientEditor),
new FrameworkPropertyMetadata(default(ColorGradient), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, ColorGradientPropertyChangedCallback));
public static readonly RoutedEvent ColorGradientChangedEvent =
EventManager.RegisterRoutedEvent(
nameof(ColorGradient),
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<ColorGradient>),
typeof(GradientEditor));
private bool _inCallback;
public GradientEditor(ColorGradient colorGradient)
{
DataContext = this;
InitializeComponent();
ColorGradient = colorGradient;
}
public ColorGradient ColorGradient
{
get => (ColorGradient) GetValue(ColorGradientProperty);
set => SetValue(ColorGradientProperty, value);
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private static void ColorGradientPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var editor = (GradientEditor) d;
if (editor._inCallback)
return;
editor._inCallback = true;
editor.OnPropertyChanged(nameof(ColorGradient));
editor._inCallback = false;
}
private void Rectangle_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var position = e.GetPosition((IInputElement) sender);
// Position ranges from 0.0 to 1.0
var newPosition = (float) Math.Min(1, Math.Max(0, Math.Round((position.X) / 435.0, 3, MidpointRounding.AwayFromZero)));
ColorGradient.Colors.Add(new ColorGradientColor(ColorGradient.GetColor(newPosition), newPosition));
}
}
}

View File

@ -1,32 +0,0 @@
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Shared.Screens.GradientEditor"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
x:Class="Artemis.UI.Shared.Screens.GradientEditor.GradientEditorColor"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas>
<Path x:Name="ColorStop"
Data="M13.437011,33.065002 C9.7268463,29.334181 7.812011,26.379009 4.874511,23.379009 1.687011,19.566509 0.12600673,17.206803 5.6843419E-14,14.127608 0.062010996,2.0027046 11.158781,-0.062991121 13.43702,0.0014351187 M13.438011,33.065016 C17.148173,29.334199 19.063008,26.379023 22.00051,23.379017 25.188007,19.566519 26.749013,17.206806 26.875018,14.127613 26.813007,2.002704 15.716239,-0.062987381 13.438,0.0014388781"
Stroke="{DynamicResource NormalBorderBrush}"
StrokeThickness="2"
Cursor="Hand"
MouseDown="ColorStop_MouseDown"
MouseUp="ColorStop_MouseUp"
MouseMove="ColorStop_MouseMove">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="180" />
<TranslateTransform X="14" Y="33" />
<ScaleTransform ScaleX="0.45" ScaleY="0.5" />
</TransformGroup>
</Path.RenderTransform>
<Path.Effect>
<DropShadowEffect BlurRadius="15" Opacity="0.25" Direction="180"></DropShadowEffect>
</Path.Effect>
</Path>
</Canvas>
</UserControl>

View File

@ -1,118 +0,0 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Annotations;
using Artemis.UI.Shared.Utilities;
namespace Artemis.UI.Shared.Screens.GradientEditor
{
/// <summary>
/// Interaction logic for GradientEditorColor.xaml
/// </summary>
public partial class GradientEditorColor : UserControl, INotifyPropertyChanged
{
private const double CanvasWidth = 435.0;
public static readonly DependencyProperty ColorGradientColorProperty = DependencyProperty.Register(nameof(GradientColor), typeof(ColorGradientColor), typeof(GradientEditorColor),
new FrameworkPropertyMetadata(default(ColorGradientColor), ColorGradientColorPropertyChangedCallback));
public static readonly DependencyProperty ColorGradientProperty = DependencyProperty.Register(nameof(ColorGradient), typeof(ColorGradient), typeof(GradientEditorColor),
new FrameworkPropertyMetadata(default(ColorGradient)));
private readonly Canvas _previewCanvas;
private bool _inCallback;
private double _mouseDownOffset;
private DateTime _mouseDownTime;
public GradientEditorColor()
{
InitializeComponent();
var window = Application.Current.Windows.OfType<GradientEditor>().FirstOrDefault();
_previewCanvas = UIUtilities.FindChild<Canvas>(window, "PreviewCanvas");
}
public ColorGradient ColorGradient
{
get => (ColorGradient) GetValue(ColorGradientProperty);
set => SetValue(ColorGradientProperty, value);
}
public ColorGradientColor GradientColor
{
get => (ColorGradientColor) GetValue(ColorGradientColorProperty);
set => SetValue(ColorGradientColorProperty, value);
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private static void ColorGradientColorPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = (GradientEditorColor) d;
if (self._inCallback)
return;
self._inCallback = true;
self.OnPropertyChanged(nameof(GradientColor));
self.Update();
self._inCallback = false;
}
private void Update()
{
ColorStop.SetValue(Canvas.LeftProperty, CanvasWidth * GradientColor.Position);
ColorStop.Fill = new SolidColorBrush(Color.FromArgb(
GradientColor.Color.Alpha,
GradientColor.Color.Red,
GradientColor.Color.Green,
GradientColor.Color.Blue
));
}
private void ColorStop_MouseDown(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).CaptureMouse();
_mouseDownOffset = (double) ColorStop.GetValue(Canvas.LeftProperty) - e.GetPosition(_previewCanvas).X;
_mouseDownTime = DateTime.Now;
}
private void ColorStop_MouseUp(object sender, MouseButtonEventArgs e)
{
// On regular click, select this color stop
if (DateTime.Now - _mouseDownTime <= TimeSpan.FromMilliseconds(250))
{
}
((IInputElement) sender).ReleaseMouseCapture();
e.Handled = true;
}
private void ColorStop_MouseMove(object sender, MouseEventArgs e)
{
if (!((IInputElement) sender).IsMouseCaptured)
return;
var position = e.GetPosition(_previewCanvas);
// Position ranges from 0.0 to 1.0
var newPosition = Math.Min(1, Math.Max(0, Math.Round((position.X + _mouseDownOffset) / CanvasWidth, 3, MidpointRounding.AwayFromZero)));
GradientColor.Position = (float) newPosition;
ColorGradient.OnColorValuesUpdated();
Update();
}
}
}

View File

@ -1,14 +1,14 @@
<controls:MaterialWindow x:Class="Artemis.UI.Shared.Screens.GradientEditor.GradientEditor"
<controls:MaterialWindow x:Class="Artemis.UI.Shared.Screens.GradientEditor.GradientEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:Artemis.UI.Shared.Screens.GradientEditor"
xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:shared="clr-namespace:Artemis.UI.Shared"
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
Title="Gradient Editor"
Background="{DynamicResource MaterialDesignPaper}"
@ -19,7 +19,8 @@
Icon="/Resources/Images/Logo/logo-512.png"
FadeContentIfInactive="False"
d:DesignHeight="450"
d:DesignWidth="800">
d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:GradientEditorViewModel}">
<controls:MaterialWindow.Resources>
<converters:ColorGradientToGradientStopsConverter x:Key="ColorGradientToGradientStopsConverter" />
</controls:MaterialWindow.Resources>
@ -41,43 +42,31 @@
<TextBlock Margin="15 15 0 0">Gradient</TextBlock>
<Separator Margin="15 5" />
<Grid>
<ItemsControl ItemsSource="{Binding ColorGradient.Colors}" ClipToBounds="False" Margin="15 0" MouseLeftButtonUp="Rectangle_MouseLeftButtonUp" Cursor="Cross">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Height="60" Width="437" x:Name="PreviewCanvas">
<Canvas.Background>
<VisualBrush Stretch="None" AlignmentY="Top">
<VisualBrush.Visual>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Margin="15">
<Rectangle x:Name="Preview" Width="{Binding ActualWidth, ElementName=PreviewCanvas}">
<Rectangle x:Name="Preview" Width="440" Height="40" Margin="15 0">
<Rectangle.Fill>
<LinearGradientBrush GradientStops="{Binding ColorGradient.Colors, Converter={StaticResource ColorGradientToGradientStopsConverter}}" />
<LinearGradientBrush GradientStops="{Binding ColorGradient.Stops, Converter={StaticResource ColorGradientToGradientStopsConverter}}" />
</Rectangle.Fill>
</Rectangle>
</materialDesign:Card>
</VisualBrush.Visual>
</VisualBrush>
</Canvas.Background>
</Canvas>
<ItemsControl ItemsSource="{Binding ColorStopViewModels}" Margin="15 0" MouseLeftButtonUp="{s:Action CanvasMouseDown}" Cursor="Cross">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Height="60" Width="440" x:Name="PreviewCanvas" Background="Transparent"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="40" />
<Setter Property="Canvas.Left" Value="{Binding Offset}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:GradientEditorColor
ColorGradient="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:MaterialWindow}, Path=ColorGradient}"
GradientColor="{Binding}" />
<ContentControl s:View.Model="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<TextBlock Margin="15 15 0 0">Stops</TextBlock>
<TextBlock Margin="15 15 0 0">Selected stop</TextBlock>
<Separator Margin="15 5" />
<Grid Margin="15">

View File

@ -0,0 +1,46 @@
using System.ComponentModel;
using System.Linq;
using Artemis.Core.Models.Profile;
using Stylet;
namespace Artemis.UI.Shared.Screens.GradientEditor
{
public class GradientEditorViewModel : Screen
{
public GradientEditorViewModel(ColorGradient colorGradient)
{
ColorGradient = colorGradient;
ColorStopViewModels = new BindableCollection<ColorStopViewModel>();
ColorGradient.PropertyChanged += ColorGradientOnPropertyChanged;
UpdateColorStopViewModels();
}
public BindableCollection<ColorStopViewModel> ColorStopViewModels { get; set; }
public ColorGradient ColorGradient { get; }
public double PreviewWidth => 440;
private void ColorGradientOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ColorGradient.Stops))
UpdateColorStopViewModels();
}
private void UpdateColorStopViewModels()
{
while (ColorGradient.Stops.Count > ColorStopViewModels.Count)
ColorStopViewModels.Add(new ColorStopViewModel(this));
while (ColorGradient.Stops.Count < ColorStopViewModels.Count)
ColorStopViewModels.RemoveAt(0);
var index = 0;
foreach (var colorStop in ColorGradient.Stops.OrderBy(s => s.Position))
{
var viewModel = ColorStopViewModels[index];
viewModel.Update(colorStop);
index++;
}
}
}
}

View File

@ -1,8 +1,26 @@
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Ninject.Factories;
using Artemis.UI.Shared.Screens.GradientEditor;
using Artemis.UI.Shared.Services.Interfaces;
using Ninject;
using Stylet;
namespace Artemis.UI.Shared.Services
{
public class GradientPickerService : IGradientPickerService
{
private readonly IGradientEditorVmFactory _gradientEditorVmFactory;
private readonly IWindowManager _windowManager;
public GradientPickerService(IGradientEditorVmFactory gradientEditorVmFactory, IWindowManager windowManager)
{
_gradientEditorVmFactory = gradientEditorVmFactory;
_windowManager = windowManager;
}
public void ShowGradientPicker(ColorGradient colorGradient)
{
_windowManager.ShowDialog(_gradientEditorVmFactory.Create(colorGradient));
}
}
}

View File

@ -1,7 +1,9 @@
namespace Artemis.UI.Shared.Services.Interfaces
using Artemis.Core.Models.Profile;
namespace Artemis.UI.Shared.Services.Interfaces
{
public interface IGradientPickerService : IArtemisSharedUIService
{
void ShowGradientPicker(ColorGradient colorGradient);
}
}

View File

@ -9,6 +9,7 @@ using Artemis.Core.Services.Interfaces;
using Artemis.UI.Ninject;
using Artemis.UI.Screens;
using Artemis.UI.Screens.Splash;
using Artemis.UI.Shared.Ninject;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Stylet;
using Ninject;
@ -76,10 +77,12 @@ namespace Artemis.UI
{
kernel.Settings.InjectNonPublic = true;
// Load this assembly's module
// Load the UI modules
kernel.Load<UIModule>();
kernel.Load<SharedUIModule>();
// Load the core assembly's module
kernel.Load<CoreModule>();
base.ConfigureIoC(kernel);
}

View File

@ -5,7 +5,6 @@ using Artemis.UI.Screens.Module.ProfileEditor;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services.Dialog;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Stylet;
using FluentValidation;
using Ninject.Extensions.Conventions;
@ -87,16 +86,6 @@ namespace Artemis.UI.Ninject
.InheritedFrom<IValidator>()
.BindAllInterfaces();
});
// Bind all shared UI services as singletons
Kernel.Bind(x =>
{
x.FromAssemblyContaining<IArtemisSharedUIService>()
.SelectAllClasses()
.InheritedFrom<IArtemisSharedUIService>()
.BindAllInterfaces()
.Configure(c => c.InSingletonScope());
});
}
}
}

View File

@ -27,12 +27,12 @@ namespace Artemis.Plugins.LayerBrushes.Color
GradientTypeProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds);
GradientProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds);
GradientProperty.Value.PropertyChanged += (sender, args) => CreateShader(_shaderBounds);
if (!GradientProperty.Value.Colors.Any())
if (!GradientProperty.Value.Stops.Any())
{
for (var i = 0; i < 9; i++)
{
var color = i != 8 ? SKColor.FromHsv(i * 32, 100, 100) : SKColor.FromHsv(0, 100, 100);
GradientProperty.Value.Colors.Add(new ColorGradientColor(color, 0.125f * i));
GradientProperty.Value.Stops.Add(new ColorGradientStop(color, 0.125f * i));
}
}
}
@ -74,17 +74,17 @@ namespace Artemis.Plugins.LayerBrushes.Color
case GradientType.LinearGradient:
shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(pathBounds.Width, 0),
GradientProperty.Value.GetColorsArray(),
GradientProperty.Value.GetColorPositionsArray(), SKShaderTileMode.Repeat);
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat);
break;
case GradientType.RadialGradient:
shader = SKShader.CreateRadialGradient(center, Math.Min(pathBounds.Width, pathBounds.Height),
GradientProperty.Value.GetColorsArray(),
GradientProperty.Value.GetColorPositionsArray(), SKShaderTileMode.Repeat);
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat);
break;
case GradientType.SweepGradient:
shader = SKShader.CreateSweepGradient(center,
GradientProperty.Value.GetColorsArray(),
GradientProperty.Value.GetColorPositionsArray(), SKShaderTileMode.Clamp, 0, 360);
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Clamp, 0, 360);
break;
default:
throw new ArgumentOutOfRangeException();