Initial implementation

This commit is contained in:
DarthAffe committed 2018-06-04 22:36:56 +02:00
1 parent 278e22020e
commit fd662dcf34
63 files changed
+4881

No files matched your search

@@ -0,0 +1,87 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace RGBSyncPlus.Controls
{
[TemplatePart(Name = "PART_Decoration", Type = typeof(FrameworkElement))]
[TemplatePart(Name = "PART_Content", Type = typeof(FrameworkElement))]
[TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))]
[TemplatePart(Name = "PART_MinimizeButton", Type = typeof(Button))]
[TemplatePart(Name = "PART_IconButton", Type = typeof(Button))]
public class BlurredDecorationWindow : Window
{
#region DependencyProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty BackgroundImageProperty = DependencyProperty.Register(
"BackgroundImage", typeof(ImageSource), typeof(BlurredDecorationWindow), new PropertyMetadata(default(ImageSource)));
public ImageSource BackgroundImage
{
get => (ImageSource)GetValue(BackgroundImageProperty);
set => SetValue(BackgroundImageProperty, value);
}
public static readonly DependencyProperty DecorationHeightProperty = DependencyProperty.Register(
"DecorationHeight", typeof(double), typeof(BlurredDecorationWindow), new PropertyMetadata(20.0));
public double DecorationHeight
{
get => (double)GetValue(DecorationHeightProperty);
set => SetValue(DecorationHeightProperty, value);
}
public static readonly DependencyProperty IconToolTipProperty = DependencyProperty.Register(
"IconToolTip", typeof(string), typeof(BlurredDecorationWindow), new PropertyMetadata(default(string)));
public string IconToolTip
{
get => (string)GetValue(IconToolTipProperty);
set => SetValue(IconToolTipProperty, value);
}
public static readonly DependencyProperty IconCommandProperty = DependencyProperty.Register(
"IconCommand", typeof(ICommand), typeof(BlurredDecorationWindow), new PropertyMetadata(default(ICommand)));
public ICommand IconCommand
{
get => (ICommand)GetValue(IconCommandProperty);
set => SetValue(IconCommandProperty, value);
}
// ReSharper restore InconsistentNaming
#endregion
#region Constructors
static BlurredDecorationWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BlurredDecorationWindow), new FrameworkPropertyMetadata(typeof(BlurredDecorationWindow)));
}
#endregion
#region Methods
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (GetTemplateChild("PART_Decoration") is FrameworkElement decoration)
decoration.MouseLeftButtonDown += (sender, args) => DragMove();
if (GetTemplateChild("PART_CloseButton") is Button closeButton)
closeButton.Click += (sender, args) => ApplicationManager.Instance.ExitCommand.Execute(null);
if (GetTemplateChild("PART_MinimizeButton") is Button minimizeButton)
minimizeButton.Click += (sender, args) => Hide();
if (GetTemplateChild("PART_IconButton") is Button iconButton)
iconButton.Click += (sender, args) => IconCommand?.Execute(null);
}
#endregion
}
}
+483
View File
@@ -0,0 +1,483 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using RGB.NET.Core;
using Color = RGB.NET.Core.Color;
using Point = System.Windows.Point;
using Rectangle = System.Windows.Shapes.Rectangle;
using WpfColor = System.Windows.Media.Color;
namespace RGBSyncPlus.Controls
{
[TemplatePart(Name = "PART_Selector", Type = typeof(Panel))]
[TemplatePart(Name = "PART_SliderAlpha", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderRed", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderGreen", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderBlue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderHue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderSaturation", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderValue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_Preview", Type = typeof(Rectangle))]
public class ColorSelector : Control
{
#region Properties & Fields
private bool _ignorePropertyChanged;
private bool _dragSelector;
private byte _a;
private byte _r;
private byte _g;
private byte _b;
private double _hue;
private double _saturation;
private double _value;
private Panel _selector;
private Rectangle _selectorColor;
private Grid _selectorGrip;
private Slider _sliderAlpha;
private Slider _sliderRed;
private Slider _sliderGreen;
private Slider _sliderBlue;
private Slider _sliderHue;
private Slider _sliderSaturation;
private Slider _sliderValue;
private Rectangle _preview;
private SolidColorBrush _previewBrush;
private SolidColorBrush _selectorBrush;
private LinearGradientBrush _alphaBrush;
private LinearGradientBrush _redBrush;
private LinearGradientBrush _greenBrush;
private LinearGradientBrush _blueBrush;
private LinearGradientBrush _hueBrush;
private LinearGradientBrush _saturationBrush;
private LinearGradientBrush _valueBrush;
#endregion
#region DependencyProperties
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(
"SelectedColor", typeof(Color), typeof(ColorSelector), new FrameworkPropertyMetadata(new Color(255, 0, 0),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
SelectedColorChanged));
public Color SelectedColor
{
get => (Color)GetValue(SelectedColorProperty);
set => SetValue(SelectedColorProperty, value);
}
#endregion
#region Methods
public override void OnApplyTemplate()
{
if ((_selector = GetTemplateChild("PART_Selector") as Panel) != null)
{
_selectorBrush = new SolidColorBrush();
_selectorColor = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = _selectorBrush
};
_selector.Children.Add(_selectorColor);
Rectangle selectorWhite = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = new LinearGradientBrush(WpfColor.FromRgb(255, 255, 255), WpfColor.FromArgb(0, 255, 255, 255), new Point(0, 0.5), new Point(1, 0.5))
};
_selector.Children.Add(selectorWhite);
Rectangle selectorBlack = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = new LinearGradientBrush(WpfColor.FromRgb(0, 0, 0), WpfColor.FromArgb(0, 0, 0, 0), new Point(0.5, 1), new Point(0.5, 0))
};
_selector.Children.Add(selectorBlack);
_selectorGrip = new Grid
{
VerticalAlignment = VerticalAlignment.Bottom,
HorizontalAlignment = HorizontalAlignment.Left,
SnapsToDevicePixels = true
};
_selectorGrip.Children.Add(new Ellipse
{
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
SnapsToDevicePixels = true,
Stroke = new SolidColorBrush(WpfColor.FromRgb(0, 0, 0)),
StrokeThickness = 2,
Fill = null,
Width = 12,
Height = 12
});
_selectorGrip.Children.Add(new Ellipse
{
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
SnapsToDevicePixels = true,
Stroke = new SolidColorBrush(WpfColor.FromRgb(255, 255, 255)),
StrokeThickness = 1,
Fill = null,
Width = 10,
Height = 10
});
_selector.Children.Add(_selectorGrip);
_selector.SizeChanged += (sender, args) => UpdateSelector();
_selector.MouseLeftButtonDown += (sender, args) =>
{
_dragSelector = true;
UpdateSelectorValue(args.GetPosition(_selector));
};
_selector.MouseEnter += (sender, args) =>
{
if (args.LeftButton == MouseButtonState.Pressed)
{
_dragSelector = true;
UpdateSelectorValue(args.GetPosition(_selector));
}
};
_selector.MouseLeftButtonUp += (sender, args) => _dragSelector = false;
_selector.MouseLeave += (sender, args) => _dragSelector = false;
_selector.MouseMove += (sender, args) => UpdateSelectorValue(args.GetPosition(_selector));
_selector.ClipToBounds = true;
}
if ((_sliderAlpha = GetTemplateChild("PART_SliderAlpha") as Slider) != null)
{
_alphaBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderAlpha.Background = _alphaBrush;
_sliderAlpha.ValueChanged += AChanged;
}
if ((_sliderRed = GetTemplateChild("PART_SliderRed") as Slider) != null)
{
_redBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderRed.Background = _redBrush;
_sliderRed.ValueChanged += RChanged;
}
if ((_sliderGreen = GetTemplateChild("PART_SliderGreen") as Slider) != null)
{
_greenBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderGreen.Background = _greenBrush;
_sliderGreen.ValueChanged += GChanged;
}
if ((_sliderBlue = GetTemplateChild("PART_SliderBlue") as Slider) != null)
{
_blueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderBlue.Background = _blueBrush;
_sliderBlue.ValueChanged += BChanged;
}
if ((_sliderHue = GetTemplateChild("PART_SliderHue") as Slider) != null)
{
_hueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1.0 / 6.0),
new GradientStop(new WpfColor(), 2.0 / 6.0),
new GradientStop(new WpfColor(), 3.0 / 6.0),
new GradientStop(new WpfColor(), 4.0 / 6.0),
new GradientStop(new WpfColor(), 5.0 / 6.0),
new GradientStop(new WpfColor(), 1) }));
_sliderHue.Background = _hueBrush;
_sliderHue.ValueChanged += HueChanged;
}
if ((_sliderSaturation = GetTemplateChild("PART_SliderSaturation") as Slider) != null)
{
_saturationBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderSaturation.Background = _saturationBrush;
_sliderSaturation.ValueChanged += SaturationChanged;
}
if ((_sliderValue = GetTemplateChild("PART_SliderValue") as Slider) != null)
{
_valueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderValue.Background = _valueBrush;
_sliderValue.ValueChanged += ValueChanged;
}
if ((_preview = GetTemplateChild("PART_Preview") as Rectangle) != null)
{
_previewBrush = new SolidColorBrush();
_preview.Fill = _previewBrush;
}
SetColor(SelectedColor);
}
private static void SelectedColorChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is ColorSelector cs) || !(dependencyPropertyChangedEventArgs.NewValue is Color color)) return;
cs.SetColor(color);
}
private void SetColor(Color color)
{
if (_ignorePropertyChanged) return;
SetA(color);
SetRGB(color);
SetHSV(color);
UpdateSelector();
UpdateUIColors();
}
private void AChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_a = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
Color color = new Color(_a, _r, _g, _b);
UpdateSelectedColor(color);
UpdateUIColors();
UpdateSelector();
}
private void RChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_r = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void GChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_g = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void BChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_b = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void RGBChanged()
{
Color color = new Color(_a, _r, _g, _b);
UpdateSelectedColor(color);
SetHSV(color);
UpdateUIColors();
UpdateSelector();
}
private void HueChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_hue = routedPropertyChangedEventArgs.NewValue.Clamp(0, 360);
HSVChanged();
}
private void SaturationChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_saturation = routedPropertyChangedEventArgs.NewValue.Clamp(0, 1);
HSVChanged();
}
private void ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_value = routedPropertyChangedEventArgs.NewValue.Clamp(0, 1);
HSVChanged();
}
private void HSVChanged()
{
Color color = Color.FromHSV(_a, _hue, _saturation, _value);
UpdateSelectedColor(color);
SetRGB(color);
UpdateUIColors();
UpdateSelector();
}
private void SetA(Color color)
{
_ignorePropertyChanged = true;
_a = color.A;
if (_sliderAlpha != null)
_sliderAlpha.Value = _a;
_ignorePropertyChanged = false;
}
private void SetRGB(Color color)
{
_ignorePropertyChanged = true;
_r = color.R;
if (_sliderRed != null)
_sliderRed.Value = _r;
_g = color.G;
if (_sliderGreen != null)
_sliderGreen.Value = _g;
_b = color.B;
if (_sliderBlue != null)
_sliderBlue.Value = _b;
_ignorePropertyChanged = false;
}
private void SetHSV(Color color)
{
_ignorePropertyChanged = true;
_hue = color.Hue;
if (_sliderHue != null)
_sliderHue.Value = _hue;
_saturation = color.Saturation;
if (_sliderSaturation != null)
_sliderSaturation.Value = _saturation;
_value = color.Value;
if (_sliderValue != null)
_sliderValue.Value = _value;
_ignorePropertyChanged = false;
}
private void UpdateSelectedColor(Color color)
{
_ignorePropertyChanged = true;
SelectedColor = color;
_ignorePropertyChanged = false;
}
private void UpdateSelector()
{
if (_selector == null) return;
double selectorX = (_selector.ActualWidth * _saturation) - (_selectorGrip.ActualWidth / 2);
double selectorY = (_selector.ActualHeight * _value) - (_selectorGrip.ActualHeight / 2);
if (!double.IsNaN(selectorX) && !double.IsNaN(selectorY))
_selectorGrip.Margin = new Thickness(selectorX, 0, 0, selectorY);
}
private void UpdateSelectorValue(Point mouseLocation)
{
if (!_dragSelector) return;
double saturation = mouseLocation.X / _selector.ActualWidth;
double value = 1 - (mouseLocation.Y / _selector.ActualHeight);
if (!double.IsNaN(saturation) && !double.IsNaN(value))
{
_saturation = saturation;
_value = value;
HSVChanged();
}
}
private void UpdateUIColors()
{
Color hueColor = Color.FromHSV(_hue, 1, 1);
if (_previewBrush != null)
_previewBrush.Color = WpfColor.FromArgb(_a, _r, _g, _b);
if (_selectorBrush != null)
_selectorBrush.Color = WpfColor.FromRgb(hueColor.R, hueColor.G, hueColor.B);
if (_alphaBrush != null)
{
_alphaBrush.GradientStops[0].Color = WpfColor.FromArgb(0, _r, _g, _b);
_alphaBrush.GradientStops[1].Color = WpfColor.FromArgb(255, _r, _g, _b);
}
if (_redBrush != null)
{
_redBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 0, _g, _b);
_redBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, 255, _g, _b);
}
if (_greenBrush != null)
{
_greenBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, _r, 0, _b);
_greenBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, _r, 255, _b);
}
if (_blueBrush != null)
{
_blueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, _r, _g, 0);
_blueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, _r, _g, 255);
}
if (_hueBrush != null)
{
Color referenceColor1 = Color.FromHSV(0, _saturation, _value);
Color referenceColor2 = Color.FromHSV(60, _saturation, _value);
Color referenceColor3 = Color.FromHSV(120, _saturation, _value);
Color referenceColor4 = Color.FromHSV(180, _saturation, _value);
Color referenceColor5 = Color.FromHSV(240, _saturation, _value);
Color referenceColor6 = Color.FromHSV(300, _saturation, _value);
_hueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, referenceColor1.R, referenceColor1.G, referenceColor1.B);
_hueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor2.R, referenceColor2.G, referenceColor2.B);
_hueBrush.GradientStops[2].Color = WpfColor.FromArgb(_a, referenceColor3.R, referenceColor3.G, referenceColor3.B);
_hueBrush.GradientStops[3].Color = WpfColor.FromArgb(_a, referenceColor4.R, referenceColor4.G, referenceColor4.B);
_hueBrush.GradientStops[4].Color = WpfColor.FromArgb(_a, referenceColor5.R, referenceColor5.G, referenceColor5.B);
_hueBrush.GradientStops[5].Color = WpfColor.FromArgb(_a, referenceColor6.R, referenceColor6.G, referenceColor6.B);
_hueBrush.GradientStops[6].Color = WpfColor.FromArgb(_a, referenceColor1.R, referenceColor1.G, referenceColor1.B);
}
if (_saturationBrush != null)
{
Color referenceColor = Color.FromHSV(_hue, 1, _value);
_saturationBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 255, 255, 255);
_saturationBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor.R, referenceColor.G, referenceColor.B);
}
if (_valueBrush != null)
{
Color referenceColor = Color.FromHSV(_hue, _saturation, 1);
_valueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 0, 0, 0);
_valueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor.R, referenceColor.G, referenceColor.B);
}
}
#endregion
}
}
+212
View File
@@ -0,0 +1,212 @@
using System;
using System.Windows;
using System.Windows.Controls;
namespace RGBSyncPlus.Controls
{
public class Form : Panel
{
#region DependencyProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register("RowHeight", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(24.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double RowHeight
{
get => (double)GetValue(RowHeightProperty);
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(RowHeight), "Row height can't be negative");
SetValue(RowHeightProperty, value);
}
}
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register("LabelWidth", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double LabelWidth
{
get => (double)GetValue(LabelWidthProperty);
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(RowHeight), "Label width can't be negative");
SetValue(LabelWidthProperty, value);
}
}
public static readonly DependencyProperty ElementSpacingProperty = DependencyProperty.Register("ElementSpacing", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double ElementSpacing
{
get => (double)GetValue(ElementSpacingProperty);
set => SetValue(ElementSpacingProperty, value);
}
public static readonly DependencyProperty RowSpacingProperty = DependencyProperty.Register("RowSpacing", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double RowSpacing
{
get => (double)GetValue(RowSpacingProperty);
set => SetValue(RowSpacingProperty, value);
}
// ReSharper restore InconsistentNaming
#endregion
#region AttachedProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty IsLabelProperty = DependencyProperty.RegisterAttached("IsLabel", typeof(bool), typeof(Form),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetIsLabel(UIElement element, bool value) => element.SetValue(IsLabelProperty, value);
public static bool GetIsLabel(UIElement element) => (bool)element.GetValue(IsLabelProperty);
public static readonly DependencyProperty LineBreaksProperty = DependencyProperty.RegisterAttached("LineBreaks", typeof(int), typeof(Form),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetLineBreaks(UIElement element, int value) => element.SetValue(LineBreaksProperty, value);
public static int GetLineBreaks(UIElement element) => (int)element.GetValue(LineBreaksProperty);
public static readonly DependencyProperty RowSpanProperty = DependencyProperty.RegisterAttached("RowSpan", typeof(int), typeof(Form),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetRowSpan(DependencyObject element, int value) => element.SetValue(RowSpanProperty, value);
public static int GetRowSpan(DependencyObject element) => (int)element.GetValue(RowSpanProperty);
public static readonly DependencyProperty FillProperty = DependencyProperty.RegisterAttached("Fill", typeof(bool), typeof(Form),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetFill(DependencyObject element, bool value) => element.SetValue(FillProperty, value);
public static bool GetFill(DependencyObject element) => (bool)element.GetValue(FillProperty);
// ReSharper restore InconsistentNaming
#endregion
#region Methods
protected override Size MeasureOverride(Size availableSize)
{
if (InternalChildren.Count == 0) return new Size(0, 0);
FormLayout layout = new FormLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
layout.AddElement(child, 0);
}
return new Size(layout.Width, layout.Height);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (InternalChildren.Count == 0) return new Size(0, 0);
FormLayout layout = new FormLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
foreach (UIElement child in InternalChildren)
child.Arrange(layout.AddElement(child, finalSize.Width));
return new Size(finalSize.Width, layout.Height);
}
#endregion
#region Data
private class FormLayout
{
#region Properties & Fields
private readonly double _rowHeight;
private readonly double _labelWidth;
private readonly double _elementSpacing;
private readonly double _rowSpacing;
private double _currentRowWidth;
private int _newRows = 0;
private int _rows = -1;
private double _currentMaxWidth;
public double Width => Math.Max((Math.Max(_currentMaxWidth, _currentRowWidth) - _elementSpacing), 0);
public double Height => ((_rows + 1) * _rowHeight) + (_rows * _rowSpacing);
#endregion
#region Constructors
public FormLayout(double rowHeight, double labelWidth, double elementSpacing, double rowSpacing)
{
this._rowHeight = rowHeight;
this._labelWidth = labelWidth;
this._elementSpacing = elementSpacing;
this._rowSpacing = rowSpacing;
}
#endregion
#region Methods
public Rect AddElement(UIElement element, double targetWidth)
{
bool isLabel = GetIsLabel(element);
int lineBreaks = GetLineBreaks(element);
int rowSpan = GetRowSpan(element);
double elementWidth = isLabel ? _labelWidth : element.DesiredSize.Width;
double height = _rowHeight;
if (_newRows > 0)
{
AddLineBreaks(_newRows);
_newRows = 0;
}
if (lineBreaks > 0) AddLineBreaks(lineBreaks);
else if (isLabel) AddLineBreaks(1);
else if (_rows < 0) _rows = 0;
if (!isLabel && (_currentRowWidth < _labelWidth))
_currentRowWidth = _labelWidth + _elementSpacing;
if (rowSpan > 1)
{
height = (rowSpan * _rowHeight) + ((rowSpan - 1) * _rowSpacing);
_newRows = Math.Max(_newRows, rowSpan - 1);
}
if (element is FrameworkElement fe)
fe.MaxHeight = height;
double width = elementWidth;
if ((targetWidth >= 1) && GetFill(element))
width = targetWidth - _currentRowWidth;
Rect rect = new Rect(new Point(_currentRowWidth, (_rows * _rowHeight) + (_rows * _rowSpacing)), new Size(width, height));
_currentRowWidth += width + _elementSpacing;
return rect;
}
private void AddLineBreaks(int count)
{
if (count <= 0) return;
_currentMaxWidth = Math.Max(_currentMaxWidth, _currentRowWidth);
_currentRowWidth = 0;
_rows += count;
}
#endregion
}
#endregion
}
}
+424
View File
@@ -0,0 +1,424 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
using Rectangle = System.Windows.Shapes.Rectangle;
using GradientStop = RGB.NET.Brushes.Gradients.GradientStop;
namespace RGBSyncPlus.Controls
{
[TemplatePart(Name = "PART_Gradient", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_Stops", Type = typeof(Canvas))]
public class GradientEditor : Control
{
#region Properties & Fields
private Canvas _gradientContainer;
private Canvas _stopContainer;
private readonly List<Rectangle> _previewRectangles = new List<Rectangle>();
private readonly Dictionary<GradientStop, ContentControl> _stops = new Dictionary<GradientStop, ContentControl>();
private ContentControl _draggingStop;
private AdornerLayer _adornerLayer;
private ColorPickerAdorner _adorner;
private Window _window;
#endregion
#region DepdencyProperties
public static readonly DependencyProperty GradientProperty = DependencyProperty.Register(
"Gradient", typeof(LinearGradient), typeof(GradientEditor), new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnGradientChanged));
public LinearGradient Gradient
{
get => (LinearGradient)GetValue(GradientProperty);
set => SetValue(GradientProperty, value);
}
public static readonly DependencyProperty GradientStopStyleProperty = DependencyProperty.Register(
"GradientStopStyle", typeof(Style), typeof(GradientEditor), new PropertyMetadata(default(Style)));
public Style GradientStopStyle
{
get => (Style)GetValue(GradientStopStyleProperty);
set => SetValue(GradientStopStyleProperty, value);
}
public static readonly DependencyProperty SelectedStopProperty = DependencyProperty.Register(
"SelectedStop", typeof(GradientStop), typeof(GradientEditor), new PropertyMetadata(default(GradientStop), SelectedStopChanged));
public GradientStop SelectedStop
{
get => (GradientStop)GetValue(SelectedStopProperty);
set => SetValue(SelectedStopProperty, value);
}
public static readonly DependencyProperty ColorSelectorTemplateProperty = DependencyProperty.Register(
"ColorSelectorTemplate", typeof(DataTemplate), typeof(GradientEditor), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ColorSelectorTemplate
{
get => (DataTemplate)GetValue(ColorSelectorTemplateProperty);
set => SetValue(ColorSelectorTemplateProperty, value);
}
public static readonly DependencyProperty CanAddOrDeleteStopsProperty = DependencyProperty.Register(
"CanAddOrDeleteStops", typeof(bool), typeof(GradientEditor), new PropertyMetadata(true));
public bool CanAddOrDeleteStops
{
get => (bool)GetValue(CanAddOrDeleteStopsProperty);
set => SetValue(CanAddOrDeleteStopsProperty, value);
}
#endregion
#region AttachedProperties
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached(
"IsSelected", typeof(bool), typeof(GradientEditor), new PropertyMetadata(default(bool)));
public static void SetIsSelected(DependencyObject element, bool value) => element.SetValue(IsSelectedProperty, value);
public static bool GetIsSelected(DependencyObject element) => (bool)element.GetValue(IsSelectedProperty);
#endregion
#region Constructors
public GradientEditor()
{
if (Gradient == null)
Gradient = new LinearGradient();
}
#endregion
#region Methods
public override void OnApplyTemplate()
{
if ((_gradientContainer = GetTemplateChild("PART_Gradient") as Canvas) != null)
{
_gradientContainer.SizeChanged += (sender, args) => UpdateGradientPreview();
_gradientContainer.MouseDown += GradientContainerOnMouseDown;
}
if ((_stopContainer = GetTemplateChild("PART_Stops") as Canvas) != null)
_stopContainer.SizeChanged += (sender, args) => UpdateGradientStops();
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
_window = Window.GetWindow(this);
if (_window != null)
{
_window.PreviewMouseDown += WindowMouseDown;
_window.PreviewKeyDown += (sender, args) =>
{
if (args.Key == Key.Escape)
SelectedStop = null;
};
}
UpdateGradientPreview();
UpdateGradientStops();
}
private void UpdateGradientPreview()
{
if ((_gradientContainer == null) || (Gradient == null)) return;
List<GradientStop> gradientStops = Gradient.GradientStops.OrderBy(x => x.Offset).ToList();
if (gradientStops.Count == 0)
UpdatePreviewRectangleCount(gradientStops.Count);
else if (gradientStops.Count == 1)
{
UpdatePreviewRectangleCount(gradientStops.Count);
GradientStop firstStop = gradientStops[0];
UpdatePreviewRectangle(_previewRectangles[0], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, 0, 1, firstStop.Color, firstStop.Color);
}
else
{
UpdatePreviewRectangleCount(gradientStops.Count + 1);
GradientStop firstStop = gradientStops[0];
UpdatePreviewRectangle(_previewRectangles[0], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, 0, firstStop.Offset, firstStop.Color, firstStop.Color);
for (int i = 0; i < (gradientStops.Count - 1); i++)
{
GradientStop stop = gradientStops[i];
GradientStop nextStop = gradientStops[i + 1];
Rectangle rect = _previewRectangles[i + 1];
UpdatePreviewRectangle(rect, _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, stop.Offset, nextStop.Offset, stop.Color, nextStop.Color);
}
GradientStop lastStop = gradientStops[gradientStops.Count - 1];
UpdatePreviewRectangle(_previewRectangles[_previewRectangles.Count - 1], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, lastStop.Offset, 1, lastStop.Color, lastStop.Color);
}
}
private void UpdatePreviewRectangle(Rectangle rect, double referenceWidth, double referenceHeight, double from, double to,
RGB.NET.Core.Color startColor, RGB.NET.Core.Color endColor)
{
rect.Fill = new LinearGradientBrush(Color.FromArgb(startColor.A, startColor.R, startColor.G, startColor.B),
Color.FromArgb(endColor.A, endColor.R, endColor.G, endColor.B),
new Point(0, 0.5), new Point(1, 0.5));
//DarthAffe 09.02.2018: Forced rounding to prevent render issues on resize
Canvas.SetLeft(rect, Math.Floor(referenceWidth * from.Clamp(0, 1)));
rect.Width = Math.Ceiling(referenceWidth * (to.Clamp(0, 1) - from.Clamp(0, 1)));
Canvas.SetTop(rect, 0);
rect.Height = referenceHeight;
}
private void UpdatePreviewRectangleCount(int gradientCount)
{
int countDiff = gradientCount - _previewRectangles.Count;
if (countDiff > 0)
for (int i = 0; i < countDiff; i++)
{
Rectangle rect = new Rectangle { VerticalAlignment = VerticalAlignment.Stretch };
_previewRectangles.Add(rect);
_gradientContainer.Children.Add(rect);
}
if (countDiff < 0)
for (int i = 0; i < Math.Abs(countDiff); i++)
{
int index = _previewRectangles.Count - i - 1;
Rectangle rect = _previewRectangles[index];
_previewRectangles.RemoveAt(index);
_gradientContainer.Children.Remove(rect);
}
}
private void UpdateGradientStops()
{
if (Gradient == null) return;
List<GradientStop> gradientStops = Gradient.GradientStops.OrderBy(x => x.Offset).ToList();
UpdateGradientStopsCount(gradientStops);
foreach (GradientStop stop in gradientStops)
UpdateGradientStop(_stops[stop], _stopContainer.ActualWidth, _stopContainer.ActualHeight, stop);
}
private void UpdateGradientStop(ContentControl control, double referenceWidth, double referenceHeight, GradientStop stop)
{
control.Background = new SolidColorBrush(Color.FromArgb(stop.Color.A, stop.Color.R, stop.Color.G, stop.Color.B));
Canvas.SetLeft(control, (referenceWidth * stop.Offset.Clamp(0, 1)) - (control.Width / 2.0));
Canvas.SetTop(control, 0);
control.Height = referenceHeight;
}
private void UpdateGradientStopsCount(List<GradientStop> gradientStops)
{
foreach (GradientStop stop in gradientStops)
{
if (!_stops.ContainsKey(stop))
{
ContentControl control = new ContentControl
{
VerticalAlignment = VerticalAlignment.Stretch,
Style = GradientStopStyle,
Content = stop
};
control.MouseDown += GradientStopOnMouseDown;
_stops.Add(stop, control);
_stopContainer.Children.Add(control);
}
}
List<GradientStop> stopsToRemove = new List<GradientStop>();
foreach (KeyValuePair<GradientStop, ContentControl> stopPair in _stops)
if (!gradientStops.Contains(stopPair.Key))
{
ContentControl control = stopPair.Value;
control.MouseDown -= GradientStopOnMouseDown;
stopsToRemove.Add(stopPair.Key);
_stopContainer.Children.Remove(control);
}
foreach (GradientStop stop in stopsToRemove)
_stops.Remove(stop);
}
private void AttachGradient(AbstractGradient gradient) => gradient.GradientChanged += GradientChanged;
private void DetachGradient(AbstractGradient gradient) => gradient.GradientChanged -= GradientChanged;
private void GradientChanged(object o, EventArgs eventArgs)
{
UpdateGradientPreview();
UpdateGradientStops();
}
private static void OnGradientChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is GradientEditor ge)) return;
if (dependencyPropertyChangedEventArgs.OldValue is AbstractGradient oldGradient)
ge.DetachGradient(oldGradient);
if (dependencyPropertyChangedEventArgs.NewValue is AbstractGradient newGradient)
ge.AttachGradient(newGradient);
}
private void GradientContainerOnMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if ((mouseButtonEventArgs.ChangedButton != MouseButton.Left) || (Gradient == null) || !CanAddOrDeleteStops) return;
double offset = mouseButtonEventArgs.GetPosition(_gradientContainer).X / _gradientContainer.ActualWidth;
RGB.NET.Core.Color color = Gradient.GetColor(offset);
GradientStop newStop = new GradientStop(offset, color);
Gradient.GradientStops.Add(newStop);
SelectedStop = newStop;
}
private void GradientStopOnMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if (!((o as ContentControl)?.Content is GradientStop stop) || (Gradient == null)) return;
if (mouseButtonEventArgs.ChangedButton == MouseButton.Right)
{
if (CanAddOrDeleteStops)
Gradient.GradientStops.Remove(stop);
}
else if (mouseButtonEventArgs.ChangedButton == MouseButton.Left)
{
SelectedStop = stop;
_draggingStop = (ContentControl)o;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_draggingStop?.Content is GradientStop stop)
{
double location = e.GetPosition(_gradientContainer).X;
stop.Offset = (location / _gradientContainer.ActualWidth).Clamp(0, 1);
}
}
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
_draggingStop = null;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
_draggingStop = null;
}
private static void SelectedStopChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is GradientEditor gradientEditor)) return;
if (gradientEditor._adorner != null)
gradientEditor._adornerLayer.Remove(gradientEditor._adorner);
if (dependencyPropertyChangedEventArgs.OldValue is GradientStop oldStop)
{
if (gradientEditor._stops.TryGetValue(oldStop, out ContentControl oldcontrol))
SetIsSelected(oldcontrol, false);
}
if (dependencyPropertyChangedEventArgs.NewValue is GradientStop stop)
{
ContentControl stopContainer = gradientEditor._stops[stop];
SetIsSelected(stopContainer, true);
if (gradientEditor._adornerLayer != null)
{
ContentControl contentControl = new ContentControl
{
ContentTemplate = gradientEditor.ColorSelectorTemplate,
Content = stop
};
ColorPickerAdorner adorner = new ColorPickerAdorner(stopContainer, contentControl);
gradientEditor._adorner = adorner;
gradientEditor._adornerLayer.Add(adorner);
}
}
}
private void WindowMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if ((_adorner != null) && (VisualTreeHelper.HitTest(_adorner, mouseButtonEventArgs.GetPosition(_adorner)) == null))
SelectedStop = null;
}
#endregion
}
public class ColorPickerAdorner : Adorner
{
#region Properties & Fields
private readonly VisualCollection _visualChildren;
private readonly FrameworkElement _colorSelector;
protected override int VisualChildrenCount => 1;
protected override Visual GetVisualChild(int index) => _colorSelector;
#endregion
#region Constructors
public ColorPickerAdorner(UIElement adornedElement, FrameworkElement colorSelector)
: base(adornedElement)
{
this._colorSelector = colorSelector;
_visualChildren = new VisualCollection(this) { colorSelector };
}
#endregion
#region Methods
protected override Size ArrangeOverride(Size finalSize)
{
Window referenceWindow = Window.GetWindow(AdornedElement);
Point referenceLocation = AdornedElement.TranslatePoint(new Point(0, 0), referenceWindow);
double referenceWidth = ((FrameworkElement)AdornedElement).ActualWidth / 2.0;
double referenceHeight = ((FrameworkElement)AdornedElement).Height;
double referenceX = referenceLocation.X + referenceWidth;
double halfWidth = finalSize.Width / 2.0;
double maxOffset = referenceWindow.Width - halfWidth;
double offset = (referenceX < halfWidth ? referenceX
: (((referenceX + (referenceWidth * 2)) > maxOffset)
? halfWidth - ((maxOffset - referenceX) - (referenceWidth * 2))
: halfWidth));
_colorSelector.Arrange(new Rect(new Point(referenceWidth - offset, referenceHeight), finalSize));
return _colorSelector.RenderSize;
}
protected override Size MeasureOverride(Size constraint)
{
_colorSelector.Measure(constraint);
return _colorSelector.DesiredSize;
}
#endregion
}
}
+51
View File
@@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace RGBSyncPlus.Controls
{
public class ImageButton : Button
{
#region Properties & Fields
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
"Image", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(default(ImageSource)));
public ImageSource Image
{
get => (ImageSource)GetValue(ImageProperty);
set => SetValue(ImageProperty, value);
}
public static readonly DependencyProperty HoverImageProperty = DependencyProperty.Register(
"HoverImage", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(default(ImageSource)));
public ImageSource HoverImage
{
get => (ImageSource)GetValue(HoverImageProperty);
set => SetValue(HoverImageProperty, value);
}
public static readonly DependencyProperty PressedImageProperty = DependencyProperty.Register(
"PressedImage", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(default(ImageSource)));
public ImageSource PressedImage
{
get => (ImageSource)GetValue(PressedImageProperty);
set => SetValue(PressedImageProperty, value);
}
// ReSharper restore InconsistentNaming
#endregion
#region Constructors
static ImageButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton)));
}
#endregion
}
}