1
0
mirror of https://github.com/DarthAffe/RGBSyncPlus synced 2025-12-12 17:08:31 +00:00

Initial implementation

This commit is contained in:
Darth Affe 2018-06-04 22:36:56 +02:00
parent 278e22020e
commit fd662dcf34
63 changed files with 4881 additions and 0 deletions

6
RGBSync+/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

26
RGBSync+/App.xaml Normal file
View File

@ -0,0 +1,26 @@
<Application x:Class="RGBSyncPlus.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:rgbSyncPlus="clr-namespace:RGBSyncPlus">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Resources/RGBSync+.xaml" />
</ResourceDictionary.MergedDictionaries>
<tb:TaskbarIcon x:Key="TaskbarIcon"
IconSource="Resources/argebee.ico"
ToolTip="Keyboard Audio-Visualizer"
MenuActivation="RightClick">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Open Configuration" Command="{Binding Source={x:Static rgbSyncPlus:ApplicationManager.Instance}, Path=OpenConfigurationCommand}" />
<MenuItem Header="Exit" Command="{Binding Source={x:Static rgbSyncPlus:ApplicationManager.Instance}, Path=ExitCommand}" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
</ResourceDictionary>
</Application.Resources>
</Application>

78
RGBSync+/App.xaml.cs Normal file
View File

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Hardcodet.Wpf.TaskbarNotification;
using Newtonsoft.Json;
using RGBSyncPlus.Configuration;
using RGBSyncPlus.Configuration.Legacy;
using RGBSyncPlus.Helper;
namespace RGBSyncPlus
{
public partial class App : Application
{
#region Constants
private const string PATH_SETTINGS = "Settings.json";
#endregion
#region Properties & Fields
private TaskbarIcon _taskbarIcon;
#endregion
#region Methods
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(int.MaxValue));
_taskbarIcon = (TaskbarIcon)FindResource("TaskbarIcon");
_taskbarIcon.DoubleClickCommand = ApplicationManager.Instance.OpenConfigurationCommand;
Settings settings = null;
try { settings = JsonConvert.DeserializeObject<Settings>(File.ReadAllText(PATH_SETTINGS), new ColorSerializer()); }
catch (Exception ex)
{
Console.WriteLine(ex.Message);
/* File doesn't exist or is corrupt - just create a new one. */
}
if (settings == null)
{
settings = new Settings { Version = Settings.CURRENT_VERSION };
_taskbarIcon.ShowBalloonTip("RGBSync+ is starting in the tray!", "Click on the icon to open the configuration.", BalloonIcon.Info);
}
else if (settings.Version != Settings.CURRENT_VERSION)
ConfigurationUpdates.PerformOn(settings);
ApplicationManager.Instance.Settings = settings;
ApplicationManager.Instance.Initialize();
}
catch (Exception ex)
{
File.WriteAllText("error.log", $"[{DateTime.Now:G}] Exception!\r\n\r\nMessage:\r\n{ex.GetFullMessage()}\r\n\r\nStackTrace:\r\n{ex.StackTrace}\r\n\r\n");
MessageBox.Show("An error occured while starting RGBSync+.\r\nMore information can be found in the error.log file in the application directory.", "Can't start RGBSync+.");
try { ApplicationManager.Instance.ExitCommand.Execute(null); }
catch { Environment.Exit(0); }
}
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
File.WriteAllText(PATH_SETTINGS, JsonConvert.SerializeObject(ApplicationManager.Instance.Settings, new ColorSerializer()));
}
#endregion
}
}

View File

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using RGB.NET.Core;
using RGB.NET.Groups;
using RGBSyncPlus.Brushes;
using RGBSyncPlus.Configuration;
using RGBSyncPlus.Helper;
using RGBSyncPlus.Model;
using RGBSyncPlus.UI;
namespace RGBSyncPlus
{
public class ApplicationManager
{
#region Constants
private const string DEVICEPROVIDER_DIRECTORY = "DeviceProvider";
#endregion
#region Properties & Fields
public static ApplicationManager Instance { get; } = new ApplicationManager();
private ConfigurationWindow _configurationWindow;
public Settings Settings { get; set; }
public TimerUpdateTrigger UpdateTrigger { get; private set; }
#endregion
#region Commands
private ActionCommand _openConfiguration;
public ActionCommand OpenConfigurationCommand => _openConfiguration ?? (_openConfiguration = new ActionCommand(OpenConfiguration));
private ActionCommand _exitCommand;
public ActionCommand ExitCommand => _exitCommand ?? (_exitCommand = new ActionCommand(Exit));
#endregion
#region Constructors
private ApplicationManager() { }
#endregion
#region Methods
public void Initialize()
{
RGBSurface surface = RGBSurface.Instance;
LoadDeviceProviders();
surface.AlignDevices();
foreach (IRGBDevice device in surface.Devices)
device.UpdateMode = DeviceUpdateMode.Sync | DeviceUpdateMode.SyncBack;
UpdateTrigger = new TimerUpdateTrigger { UpdateFrequency = 1.0 / MathHelper.Clamp(Settings.UpdateRate, 1, 100) };
surface.RegisterUpdateTrigger(UpdateTrigger);
UpdateTrigger.Start();
foreach (SyncGroup syncGroup in Settings.SyncGroups)
RegisterSyncGroup(syncGroup);
}
private void LoadDeviceProviders()
{
string deviceProvierDir = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? string.Empty, DEVICEPROVIDER_DIRECTORY);
if (!Directory.Exists(deviceProvierDir)) return;
foreach (string file in Directory.GetFiles(deviceProvierDir, "*.dll"))
{
try
{
Assembly assembly = Assembly.LoadFrom(file);
foreach (Type loaderType in assembly.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && t.IsClass
&& typeof(IRGBDeviceProviderLoader).IsAssignableFrom(t)))
{
if (Activator.CreateInstance(loaderType) is IRGBDeviceProviderLoader deviceProviderLoader)
{
//TODO DarthAffe 03.06.2018: Support Initialization
if (deviceProviderLoader.RequiresInitialization) continue;
RGBSurface.Instance.LoadDevices(deviceProviderLoader);
}
}
}
catch { /* #sadprogrammer */ }
}
}
public void AddSyncGroup(SyncGroup syncGroup)
{
Settings.SyncGroups.Add(syncGroup);
RegisterSyncGroup(syncGroup);
}
private void RegisterSyncGroup(SyncGroup syncGroup)
{
syncGroup.LedGroup = new ListLedGroup(syncGroup.Leds.GetLeds()) { Brush = new SyncBrush(syncGroup) };
syncGroup.LedsChangedEventHandler = (sender, args) => UpdateLedGroup(syncGroup.LedGroup, args);
syncGroup.Leds.CollectionChanged += syncGroup.LedsChangedEventHandler;
}
public void RemoveSyncGroup(SyncGroup syncGroup)
{
Settings.SyncGroups.Remove(syncGroup);
syncGroup.Leds.CollectionChanged -= syncGroup.LedsChangedEventHandler;
syncGroup.LedGroup.Detach();
syncGroup.LedGroup = null;
}
private void UpdateLedGroup(ListLedGroup group, NotifyCollectionChangedEventArgs args)
{
if (args.Action == NotifyCollectionChangedAction.Reset)
{
List<Led> leds = group.GetLeds().ToList();
group.RemoveLeds(leds);
}
else
{
if (args.NewItems != null)
group.AddLeds(args.NewItems.Cast<SyncLed>().GetLeds());
if (args.OldItems != null)
group.RemoveLeds(args.OldItems.Cast<SyncLed>().GetLeds());
}
}
private void OpenConfiguration()
{
if (_configurationWindow == null) _configurationWindow = new ConfigurationWindow();
_configurationWindow.Show();
}
private void Exit()
{
try { RGBSurface.Instance?.Dispose(); } catch { /* well, we're shuting down anyway ... */ }
Application.Current.Shutdown();
}
#endregion
}
}

View File

@ -0,0 +1,111 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace RGBSyncPlus.Attached
{
public static class SliderValue
{
#region Properties & Fields
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty UnitProperty = DependencyProperty.RegisterAttached(
"Unit", typeof(string), typeof(SliderValue), new PropertyMetadata(default(string)));
public static void SetUnit(DependencyObject element, string value) => element.SetValue(UnitProperty, value);
public static string GetUnit(DependencyObject element) => (string)element.GetValue(UnitProperty);
public static readonly DependencyProperty IsShownProperty = DependencyProperty.RegisterAttached(
"IsShown", typeof(bool), typeof(SliderValue), new PropertyMetadata(default(bool), IsShownChanged));
public static void SetIsShown(DependencyObject element, bool value) => element.SetValue(IsShownProperty, value);
public static bool GetIsShown(DependencyObject element) => (bool)element.GetValue(IsShownProperty);
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.RegisterAttached(
"BorderBrush", typeof(Brush), typeof(SliderValue), new PropertyMetadata(default(Brush)));
public static void SetBorderBrush(DependencyObject element, Brush value) => element.SetValue(BorderBrushProperty, value);
public static Brush GetBorderBrush(DependencyObject element) => (Brush)element.GetValue(BorderBrushProperty);
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(
"Background", typeof(Brush), typeof(SliderValue), new PropertyMetadata(default(Brush)));
public static void SetBackground(DependencyObject element, Brush value) => element.SetValue(BackgroundProperty, value);
public static Brush GetBackground(DependencyObject element) => (Brush)element.GetValue(BackgroundProperty);
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached(
"Foreground", typeof(Brush), typeof(SliderValue), new PropertyMetadata(default(Brush)));
public static void SetForeground(DependencyObject element, Brush value) => element.SetValue(ForegroundProperty, value);
public static Brush GetForeground(DependencyObject element) => (Brush)element.GetValue(ForegroundProperty);
public static readonly DependencyProperty FontProperty = DependencyProperty.RegisterAttached(
"Font", typeof(FontFamily), typeof(SliderValue), new PropertyMetadata(default(FontFamily)));
public static void SetFont(DependencyObject element, FontFamily value) => element.SetValue(FontProperty, value);
public static FontFamily GetFont(DependencyObject element) => (FontFamily)element.GetValue(FontProperty);
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached(
"FontSize", typeof(double), typeof(SliderValue), new PropertyMetadata(default(double)));
public static void SetFontSize(DependencyObject element, double value) => element.SetValue(FontSizeProperty, value);
public static double GetFontSize(DependencyObject element) => (double)element.GetValue(FontSizeProperty);
// ReSharper enable InconsistentNaming
#endregion
#region Methods
private static void IsShownChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is Slider slider)) return;
if (dependencyPropertyChangedEventArgs.NewValue as bool? == true)
{
slider.MouseEnter += SliderOnMouseEnter;
slider.MouseLeave += SliderOnMouseLeave;
}
else
{
slider.MouseEnter -= SliderOnMouseEnter;
slider.MouseLeave -= SliderOnMouseLeave;
RemoveAdorner(slider);
}
}
private static void SliderOnMouseEnter(object sender, MouseEventArgs mouseEventArgs)
{
if (!(sender is Slider slider)) return;
AdornerLayer.GetAdornerLayer(slider)?.Add(new SliderValueAdorner(slider, GetUnit(slider))
{
BorderBrush = GetBorderBrush(slider),
Background = GetBackground(slider),
Foreground = GetForeground(slider),
Font = GetFont(slider),
FontSize = GetFontSize(slider)
});
}
private static void SliderOnMouseLeave(object sender, MouseEventArgs mouseEventArgs)
{
if (!(sender is Slider slider)) return;
RemoveAdorner(slider);
}
private static void RemoveAdorner(Slider slider)
{
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(slider);
Adorner adorner = adornerLayer?.GetAdorners(slider)?.FirstOrDefault(x => x is SliderValueAdorner);
if (adorner != null)
{
adornerLayer.Remove(adorner);
(adorner as SliderValueAdorner)?.Cleanup();
}
}
#endregion
}
}

View File

@ -0,0 +1,99 @@
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using Point = System.Windows.Point;
namespace RGBSyncPlus.Attached
{
public class SliderValueAdorner : System.Windows.Documents.Adorner
{
#region Properties & Fields
private readonly string _unit;
private readonly Slider _slider;
private readonly Thumb _thumb;
private readonly RepeatButton _decreaseRepeatButton;
public Brush BorderBrush { get; set; } = System.Windows.Media.Brushes.Black;
public Brush Background { get; set; } = System.Windows.Media.Brushes.Black;
public Brush Foreground { get; set; } = System.Windows.Media.Brushes.White;
public FontFamily Font { get; set; } = new FontFamily("Verdana");
public double FontSize { get; set; } = 14;
#endregion
#region Constructors
public SliderValueAdorner(UIElement adornedElement, string unit)
: base(adornedElement)
{
this._unit = unit;
_slider = (Slider)adornedElement;
Track track = (Track)_slider.Template.FindName("PART_Track", _slider);
_thumb = track.Thumb;
_decreaseRepeatButton = track.DecreaseRepeatButton;
_decreaseRepeatButton.SizeChanged += OnButtonSizeChanged;
}
#endregion
#region Methods
public void Cleanup()
{
_decreaseRepeatButton.SizeChanged -= OnButtonSizeChanged;
}
private void OnButtonSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs) => InvalidateVisual();
protected override void OnRender(DrawingContext drawingContext)
{
double offset = _decreaseRepeatButton.ActualWidth + (_thumb.ActualWidth / 2.0);
FormattedText text = new FormattedText(GetText(), CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(Font, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), FontSize, Foreground);
Geometry border = CreateBorder(offset, text.Width, text.Height);
drawingContext.DrawGeometry(Background, new Pen(BorderBrush, 1), border);
drawingContext.DrawText(text, new Point(offset - (text.Width / 2.0), -26));
}
private string GetText()
{
string valueText = _slider.Value.ToString();
if (!string.IsNullOrWhiteSpace(_unit))
valueText += " " + _unit;
return valueText;
}
private Geometry CreateBorder(double offset, double width, double height)
{
double halfWidth = width / 2.0;
PathGeometry borderGeometry = new PathGeometry();
PathFigure border = new PathFigure
{
StartPoint = new Point(offset, 0),
IsClosed = true,
IsFilled = true
};
border.Segments.Add(new LineSegment(new Point(offset + 4, -6), true));
border.Segments.Add(new LineSegment(new Point(offset + 4 + halfWidth, -6), true));
border.Segments.Add(new LineSegment(new Point(offset + 4 + halfWidth, -10 - height), true));
border.Segments.Add(new LineSegment(new Point(offset - 4 - halfWidth, -10 - height), true));
border.Segments.Add(new LineSegment(new Point(offset - 4 - halfWidth, -6), true));
border.Segments.Add(new LineSegment(new Point(offset - 4, -6), true));
borderGeometry.Figures.Add(border);
return borderGeometry;
}
#endregion
}
}

View File

@ -0,0 +1,48 @@
using System.ComponentModel;
using RGB.NET.Core;
using RGBSyncPlus.Helper;
using RGBSyncPlus.Model;
namespace RGBSyncPlus.Brushes
{
public class SyncBrush : AbstractBrush
{
#region Properties & Fields
private readonly SyncGroup _syncGroup;
private Led _syncLed;
#endregion
#region Constructors
public SyncBrush(SyncGroup syncGroup)
{
this._syncGroup = syncGroup;
syncGroup.PropertyChanged += SyncGroupOnPropertyChanged;
_syncLed = syncGroup.SyncLed?.GetLed();
}
#endregion
#region Methods
private void SyncGroupOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(SyncGroup.SyncLed))
_syncLed = _syncGroup.SyncLed?.GetLed();
}
protected override Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget)
{
if (renderTarget.Led == _syncLed)
return Color.Transparent;
return _syncLed?.Color ?? Color.Transparent;
}
#endregion
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using RGB.NET.Core;
namespace RGBSyncPlus.Configuration
{
public class AbstractConfiguration : AbstractBindable, IConfiguration, INotifyPropertyChanged
{
#region Methods
protected override bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if ((typeof(T) == typeof(double)) || (typeof(T) == typeof(float)))
{
if (Math.Abs((double)(object)storage - (double)(object)value) < 0.000001) return false;
}
else
{
if (Equals(storage, value)) return false;
}
storage = value;
// ReSharper disable once ExplicitCallerInfoArgument
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
}

View File

@ -0,0 +1,41 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RGB.NET.Core;
namespace RGBSyncPlus.Configuration
{
public class ColorSerializer : JsonConverter
{
#region Methods
public override bool CanConvert(Type objectType) => objectType == typeof(Color);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (!(value is Color color)) return;
writer.WriteStartObject();
writer.WritePropertyName("A");
writer.WriteValue(color.A);
writer.WritePropertyName("R");
writer.WriteValue(color.R);
writer.WritePropertyName("G");
writer.WriteValue(color.G);
writer.WritePropertyName("B");
writer.WriteValue(color.B);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jsonObject = JObject.Load(reader);
return new Color(jsonObject.Property("A").Value.ToObject<byte>(),
jsonObject.Property("R").Value.ToObject<byte>(),
jsonObject.Property("G").Value.ToObject<byte>(),
jsonObject.Property("B").Value.ToObject<byte>());
}
#endregion
}
}

View File

@ -0,0 +1,7 @@
using System.ComponentModel;
namespace RGBSyncPlus.Configuration
{
public interface IConfiguration : INotifyPropertyChanged
{ }
}

View File

@ -0,0 +1,12 @@
namespace RGBSyncPlus.Configuration.Legacy
{
public static class ConfigurationUpdates
{
#region Methods
public static void PerformOn(Settings settings)
{ }
#endregion
}
}

View File

@ -0,0 +1,24 @@
using System.Collections.Generic;
using RGBSyncPlus.Model;
namespace RGBSyncPlus.Configuration
{
public class Settings
{
#region Constants
public const int CURRENT_VERSION = 1;
#endregion
#region Properties & Fields
public int Version { get; set; } = 0;
public double UpdateRate { get; set; } = 30.0;
public List<SyncGroup> SyncGroups { get; set; } = new List<SyncGroup>();
#endregion
}
}

View File

@ -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
}
}

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
RGBSync+/Controls/Form.cs Normal file
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
}
}

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
}
}

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
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace RGBSyncPlus.Converter
{
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
#region Methods
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> (value as bool?) == true ? Visibility.Visible
: (string.Equals(parameter?.ToString(), "true", StringComparison.OrdinalIgnoreCase) ? Visibility.Hidden : Visibility.Collapsed);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => value as Visibility? == Visibility.Visible;
#endregion
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace RGBSyncPlus.Converter
{
[ValueConversion(typeof(object), typeof(bool))]
public class EqualsToBoolConverter : IValueConverter
{
#region Methods
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => Equals(value, parameter);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException();
#endregion
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace RGBSyncPlus.Converter
{
[ValueConversion(typeof(object), typeof(Visibility))]
public class NullToVisibilityConverter : IValueConverter
{
#region Methods
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> (value == null) == (string.Equals(parameter?.ToString(), "true", StringComparison.OrdinalIgnoreCase)) ? Visibility.Visible : Visibility.Hidden;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException();
#endregion
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace RGBSyncPlus.Converter
{
public class ScrollOffsetToOpacityMaskConverter : IMultiValueConverter
{
#region Constants
private static readonly Color TRANSPARENT = Color.FromArgb(0, 0, 0, 0);
private static readonly Color OPAQUE = Color.FromArgb(255, 0, 0, 0);
#endregion
#region Methods
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double offset = double.Parse(values[0].ToString());
double maxHeight = double.Parse(values[1].ToString());
double height = double.Parse(values[2].ToString());
double transparencyHeight = double.Parse(parameter.ToString());
double transparencyFactor = (transparencyHeight - 6) / height;
double transparencyFadeFactor = (transparencyHeight + 4) / height;
bool top = !(Math.Abs(offset) < float.Epsilon);
bool bot = !(Math.Abs(offset - maxHeight) < float.Epsilon);
if (!top && !bot) return new SolidColorBrush(OPAQUE);
GradientStopCollection gradientStops = new GradientStopCollection();
if (top)
{
gradientStops.Add(new GradientStop(TRANSPARENT, 0.0));
gradientStops.Add(new GradientStop(TRANSPARENT, transparencyFactor));
gradientStops.Add(new GradientStop(OPAQUE, transparencyFadeFactor));
}
else
gradientStops.Add(new GradientStop(OPAQUE, 0.0));
if (bot)
{
gradientStops.Add(new GradientStop(OPAQUE, 1.0 - transparencyFadeFactor));
gradientStops.Add(new GradientStop(TRANSPARENT, 1.0 - transparencyFactor));
gradientStops.Add(new GradientStop(TRANSPARENT, 1.0));
}
else
gradientStops.Add(new GradientStop(OPAQUE, 1.0));
return new LinearGradientBrush(gradientStops, new Point(0.5, 0.0), new Point(0.5, 1.0));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException();
#endregion
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace RGBSyncPlus.Converter
{
// Based on: http://stackoverflow.com/a/28679767
public class ScrollOffsetToVisibilityConverter : IMultiValueConverter
{
#region Methods
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool top = "top".Equals(parameter?.ToString(), StringComparison.OrdinalIgnoreCase);
double offset = double.Parse(values[0].ToString());
double maxHeight = double.Parse(values[1].ToString());
return (top && Math.Abs(offset) < float.Epsilon) || (!top && Math.Abs(offset - maxHeight) < float.Epsilon)
? Visibility.Collapsed
: Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException();
#endregion
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Windows.Input;
namespace RGBSyncPlus.Helper
{
public class ActionCommand : ICommand
{
#region Properties & Fields
private readonly Func<bool> _canExecute;
private readonly Action _command;
#endregion
#region Events
public event EventHandler CanExecuteChanged;
#endregion
#region Constructors
public ActionCommand(Action command, Func<bool> canExecute = null)
{
this._command = command;
this._canExecute = canExecute;
}
#endregion
#region Methods
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
public void Execute(object parameter) => _command?.Invoke();
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());
#endregion
}
public class ActionCommand<T> : ICommand
{
#region Properties & Fields
private readonly Func<T, bool> _canExecute;
private readonly Action<T> _command;
#endregion
#region Events
public event EventHandler CanExecuteChanged;
#endregion
#region Constructors
public ActionCommand(Action<T> command, Func<T, bool> canExecute = null)
{
this._command = command;
this._canExecute = canExecute;
}
#endregion
#region Methods
public bool CanExecute(object parameter) => _canExecute?.Invoke((T)parameter) ?? true;
public void Execute(object parameter) => _command?.Invoke((T)parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());
#endregion
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace RGBSyncPlus.Helper
{
public static class ExceptionExtension
{
#region Methods
public static string GetFullMessage(this Exception ex, string message = "")
{
if (ex == null) return string.Empty;
message += ex.Message;
if (ex.InnerException != null)
message += "\r\nInnerException: " + GetFullMessage(ex.InnerException);
return message;
}
#endregion
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace RGBSyncPlus.Helper
{
public static class MathHelper
{
#region Methods
public static double Clamp(double value, double min, double max) => Math.Max(min, Math.Min(max, value));
public static float Clamp(float value, float min, float max) => (float)Clamp((double)value, min, max);
public static int Clamp(int value, int min, int max) => Math.Max(min, Math.Min(max, value));
#endregion
}
}

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGBSyncPlus.Model;
namespace RGBSyncPlus.Helper
{
public static class RGBNetExtension
{
public static string GetDeviceName(this IRGBDevice device) => $"{device.DeviceInfo.Manufacturer} {device.DeviceInfo.Model} ({device.DeviceInfo.DeviceType})";
public static IEnumerable<Led> GetLeds(this IEnumerable<SyncLed> syncLeds)
=> syncLeds.Select(GetLed).Where(led => led != null);
public static Led GetLed(this SyncLed syncLed)
{
if (syncLed == null) return null;
return RGBSurface.Instance.Leds.FirstOrDefault(l => (l.Id == syncLed.LedId) && (l.Device.GetDeviceName() == syncLed.Device));
}
}
}

View File

@ -0,0 +1,48 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Newtonsoft.Json;
using RGB.NET.Core;
using RGB.NET.Groups;
namespace RGBSyncPlus.Model
{
public class SyncGroup : AbstractBindable
{
#region Properties & Fields
public string DisplayName => string.IsNullOrWhiteSpace(Name) ? "(unnamed)" : Name;
private string _name;
public string Name
{
get => _name;
set
{
if (SetProperty(ref _name, value))
OnPropertyChanged(nameof(DisplayName));
}
}
private SyncLed _syncLed;
public SyncLed SyncLed
{
get => _syncLed;
set => SetProperty(ref _syncLed, value);
}
private ObservableCollection<SyncLed> _leds = new ObservableCollection<SyncLed>();
public ObservableCollection<SyncLed> Leds
{
get => _leds;
set => SetProperty(ref _leds, value);
}
[JsonIgnore]
public ListLedGroup LedGroup { get; set; }
[JsonIgnore]
public NotifyCollectionChangedEventHandler LedsChangedEventHandler { get; set; }
#endregion
}
}

80
RGBSync+/Model/SyncLed.cs Normal file
View File

@ -0,0 +1,80 @@
using Newtonsoft.Json;
using RGB.NET.Core;
using RGBSyncPlus.Helper;
namespace RGBSyncPlus.Model
{
public class SyncLed : AbstractBindable
{
#region Properties & Fields
private string _device;
public string Device
{
get => _device;
set => SetProperty(ref _device, value);
}
private LedId _ledId;
public LedId LedId
{
get => _ledId;
set => SetProperty(ref _ledId, value);
}
private Led _led;
[JsonIgnore]
public Led Led
{
get => _led;
set => SetProperty(ref _led, value);
}
#endregion
#region Constructors
public SyncLed()
{ }
public SyncLed(string device, LedId ledId)
{
this.Device = device;
this.LedId = ledId;
}
public SyncLed(Led led)
{
this.Device = led.Device.GetDeviceName();
this.LedId = led.Id;
this.Led = led;
}
#endregion
#region Methods
protected bool Equals(SyncLed other) => string.Equals(_device, other._device) && (_ledId == other._ledId);
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SyncLed)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((_device != null ? _device.GetHashCode() : 0) * 397) ^ (int)_ledId;
}
}
public static bool operator ==(SyncLed left, SyncLed right) => Equals(left, right);
public static bool operator !=(SyncLed left, SyncLed right) => !Equals(left, right);
#endregion
}
}

View File

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RGBSync+")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RGBSync+")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RGBSyncPlus.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RGBSyncPlus.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

26
RGBSync+/Properties/Settings.Designer.cs generated Normal file
View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RGBSyncPlus.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

236
RGBSync+/RGBSync+.csproj Normal file
View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C6BF4357-07D9-496B-9630-A26568D30723}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>RGBSyncPlus</RootNamespace>
<AssemblyName>RGBSync+</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>RGBSyncPlus.App</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\argebee.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ApplicationManager.cs" />
<Compile Include="Attached\SliderValue.cs" />
<Compile Include="Attached\SliderValueAdorner.cs" />
<Compile Include="Brushes\SyncBrush.cs" />
<Compile Include="Configuration\AbstractConfiguration.cs" />
<Compile Include="Configuration\ColorSerializer.cs" />
<Compile Include="Configuration\IConfiguration.cs" />
<Compile Include="Configuration\Legacy\ConfigurationUpdates.cs" />
<Compile Include="Configuration\Settings.cs" />
<Compile Include="Converter\NullToVisibilityConverter.cs" />
<Compile Include="Converter\ScrollOffsetToOpacityMaskConverter.cs" />
<Compile Include="Converter\ScrollOffsetToVisibilityConverter.cs" />
<Compile Include="Helper\ActionCommand.cs" />
<Compile Include="Helper\RGBNetExtension.cs" />
<Compile Include="Helper\ExceptionExtension.cs" />
<Compile Include="Helper\MathHelper.cs" />
<Compile Include="Model\SyncGroup.cs" />
<Compile Include="Model\SyncLed.cs" />
<Compile Include="UI\ConfigurationViewModel.cs" />
<Compile Include="UI\ConfigurationWindow.xaml.cs">
<DependentUpon>ConfigurationWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\BlurredDecorationWindow.cs" />
<Compile Include="Controls\ColorSelector.cs" />
<Compile Include="Controls\Form.cs" />
<Compile Include="Controls\GradientEditor.cs" />
<Compile Include="Controls\ImageButton.cs" />
<Compile Include="Converter\BoolToVisibilityConverter.cs" />
<Compile Include="Converter\EqualsToBoolConverter.cs" />
<Compile Include="Styles\CachedResourceDictionary.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Styles\TextBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ListBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="UI\ConfigurationWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Resources\RGBSync+.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\BlurredDecorationWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Button.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ColorSelector.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ComboBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Form.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\FrameworkElement.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\GradientEditor.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\GroupBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ImageButton.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Navigation.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Slider.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Theme.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ToolTip.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Resource Include="Resources\font.ttf" />
<Resource Include="Resources\navigation.ttf" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="gong-wpf-dragdrop">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Hardcodet.NotifyIcon.Wpf">
<Version>1.0.8</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.2</Version>
</PackageReference>
<PackageReference Include="RGB.NET.Brushes">
<Version>0.0.1.54</Version>
</PackageReference>
<PackageReference Include="RGB.NET.Core">
<Version>0.0.1.54</Version>
</PackageReference>
<PackageReference Include="RGB.NET.Decorators">
<Version>0.0.1.54</Version>
</PackageReference>
<PackageReference Include="RGB.NET.Groups">
<Version>0.0.1.54</Version>
</PackageReference>
<PackageReference Include="System.ValueTuple">
<Version>4.5.0</Version>
</PackageReference>
<PackageReference Include="WPFTransitionals">
<Version>1.0.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\argebee.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\background.png" />
<Resource Include="Resources\close.png" />
<Resource Include="Resources\minimize.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\arrow_down.png" />
<Resource Include="Resources\arrow_up.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

25
RGBSync+/RGBSync+.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2018
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGBSync+", "RGBSync+.csproj", "{C6BF4357-07D9-496B-9630-A26568D30723}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C6BF4357-07D9-496B-9630-A26568D30723}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6BF4357-07D9-496B-9630-A26568D30723}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6BF4357-07D9-496B-9630-A26568D30723}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6BF4357-07D9-496B-9630-A26568D30723}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3AD1163D-9F77-43AB-A3BA-38C1B9CCBA87}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,42 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:RGBSyncPlus.UI"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls"
xmlns:converter="clr-namespace:RGBSyncPlus.Converter">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/BlurredDecorationWindow.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ImageButton.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Form.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/GroupBox.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ToolTip.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ComboBox.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Button.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ListBox.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Slider.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/TextBox.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ColorSelector.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/GradientEditor.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<converter:EqualsToBoolConverter x:Key="EqualsToBoolConverter" />
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converter:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<Style TargetType="{x:Type controls:BlurredDecorationWindow}" BasedOn="{StaticResource StyleBlurredDecorationWindow}" />
<Style TargetType="{x:Type ui:ConfigurationWindow}" BasedOn="{StaticResource StyleBlurredDecorationWindow}" />
<Style TargetType="{x:Type controls:ImageButton}" BasedOn="{StaticResource StyleImageButton}" />
<Style TargetType="{x:Type controls:Form}" BasedOn="{StaticResource StyleForm}" />
<Style TargetType="GroupBox" BasedOn="{StaticResource StyleGroupBoxBox}" />
<Style TargetType="ToolTip" BasedOn="{StaticResource StyleToolTip}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource StyleComboBox}" />
<Style TargetType="Button" BasedOn="{StaticResource StyleButton}" />
<Style TargetType="ListBox" BasedOn="{StaticResource StyleListBox}" />
<Style TargetType="Slider" BasedOn="{StaticResource StyleSlider}" />
<Style TargetType="TextBox" BasedOn="{StaticResource StyleTextBox}" />
</styles:CachedResourceDictionary>

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
RGBSync+/Resources/font.ttf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

View File

@ -0,0 +1,126 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ImageButton.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleImageButtonWindow"
BasedOn="{StaticResource StyleImageButtonWithOpacity}"
TargetType="{x:Type controls:ImageButton}">
<Setter Property="Padding" Value="4" />
<Setter Property="Margin" Value="4" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
</Style>
<Style x:Key="StyleBlurredDecorationWindow"
TargetType="{x:Type controls:BlurredDecorationWindow}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="ResizeMode" Value="CanResize" />
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="BorderThickness" Value="1,0,1,1" />
<Setter Property="DecorationHeight" Value="80" />
<Setter Property="BorderBrush" Value="{StaticResource BrushWindowBorder}" />
<Setter Property="Background" Value="{StaticResource BrushWindowBackground}" />
<Setter Property="BackgroundImage" Value="pack://application:,,,/Resources/background.png" />
<Setter Property="MinWidth" Value="256" />
<Setter Property="MinHeight" Value="144" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="5" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:BlurredDecorationWindow}">
<Grid Background="{TemplateBinding Background}">
<Grid Margin="-12,-12,-12,0">
<Viewbox HorizontalAlignment="Center" Stretch="UniformToFill">
<Image Source="{TemplateBinding BackgroundImage}" />
</Viewbox>
<Border Name="BlurImage">
<Border.OpacityMask>
<VisualBrush TileMode="None" Stretch="None" AlignmentX="Center" AlignmentY="Center">
<VisualBrush.Visual>
<Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}}">
<Grid.RowDefinitions>
<RowDefinition Height="12" />
<RowDefinition Height="92" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle Fill="Black" Grid.Row="0" Grid.RowSpan="2" />
<Rectangle Fill="Transparent" Grid.Row="2" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Border.OpacityMask>
<Border.Effect>
<BlurEffect Radius="30" />
</Border.Effect>
<Viewbox HorizontalAlignment="Center" Stretch="UniformToFill">
<Image Source="{TemplateBinding BackgroundImage}" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Viewbox>
</Border>
</Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel LastChildFill="True">
<Border x:Name="PART_Decoration"
DockPanel.Dock="Top"
HorizontalAlignment="Stretch"
Height="{TemplateBinding DecorationHeight}"
Background="{TemplateBinding BorderBrush}">
<DockPanel HorizontalAlignment="Stretch" Margin="4" LastChildFill="False">
<controls:ImageButton x:Name="PART_CloseButton"
DockPanel.Dock="Right"
Style="{StaticResource StyleImageButtonWindow}"
Image="pack://application:,,,/Resources/close.png"
ToolTip="Close" />
<controls:ImageButton x:Name="PART_MinimizeButton"
DockPanel.Dock="Right"
Style="{StaticResource StyleImageButtonWindow}"
Image="pack://application:,,,/Resources/minimize.png"
ToolTip="Minimize" />
<controls:ImageButton x:Name="PART_IconButton"
DockPanel.Dock="Left"
VerticalAlignment="Center"
Margin="8"
Style="{StaticResource StyleImageButtonWithOpacity}"
Image="{TemplateBinding Icon}"
ToolTip="https://github.com/DarthAffe/RGBSyncPlus" />
</DockPanel>
</Border>
<ContentPresenter x:Name="PART_Content" />
</DockPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,41 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleButton"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="Button">
<Setter Property="Foreground" Value="{StaticResource BrushButtonForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="Background" Value="{StaticResource BrushButtonBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushButtonBorder}" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Padding" Value="4,2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter Margin="{TemplateBinding Padding}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BrushButtonHover}" />
</Trigger>
</Style.Triggers>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,56 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
namespace RGBSyncPlus.Styles
{
public class CachedResourceDictionary : ResourceDictionary
{
#region Properties & Fields
// ReSharper disable InconsistentNaming
private static readonly List<string> _cachedDictionaries = new List<string>();
private static readonly ResourceDictionary _innerDictionary = new ResourceDictionary();
// ReSharper restore
public new Uri Source
{
get => null;
set
{
lock (_innerDictionary)
{
UpdateCache(value);
MergedDictionaries.Clear();
MergedDictionaries.Add(_innerDictionary);
}
}
}
#endregion
#region Methods
private static void UpdateCache(Uri source)
{
string uriPath = source.OriginalString;
if (_cachedDictionaries.Contains(uriPath)) return;
_cachedDictionaries.Add(uriPath);
ResourceDictionary newDictionary = new ResourceDictionary { Source = new Uri(uriPath, source.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative) };
CopyDictionaryEntries(newDictionary, _innerDictionary);
}
private static void CopyDictionaryEntries(IDictionary source, IDictionary target)
{
foreach (object key in source.Keys)
if (!target.Contains(key))
target.Add(key, source[key]);
}
#endregion
}
}

View File

@ -0,0 +1,305 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<DrawingBrush x:Key="BrushChessboard"
TileMode="Tile"
Viewport="0,0,16,16"
ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF808080"
Geometry="M5,5 L0,5 0,10 5,10 5,5 10,5 10,0 5,0 Z"/>
</DrawingBrush.Drawing>
</DrawingBrush>
<DrawingBrush x:Key="BrushChessboardSmall"
TileMode="Tile"
Viewport="0,0,8,8"
ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF808080"
Geometry="M5,5 L0,5 0,10 5,10 5,5 10,5 10,0 5,0 Z"/>
</DrawingBrush.Drawing>
</DrawingBrush>
<Style x:Key="StyleSliderLabel"
TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="StyleSliderValue"
TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="StyleThumbSlider"
TargetType="Thumb">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Height" Value="NaN" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border VerticalAlignment="Stretch"
Width="4"
SnapsToDevicePixels="True"
Opacity="0.66"
BorderThickness="1"
Background="#FFFFFFFF"
BorderBrush="#FF000000" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleSlider"
TargetType="Slider">
<Setter Property="Focusable" Value="False" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FF000000" />
<Setter Property="IsMoveToPointEnabled" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Border SnapsToDevicePixels="True"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="#FFFFFFFF">
<Border Margin="1"
SnapsToDevicePixels="True"
Background="{StaticResource BrushChessboardSmall}">
<Border SnapsToDevicePixels="True"
Background="{TemplateBinding Background}">
<Grid x:Name="GridTrackParent" SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Track x:Name="PART_Track"
Grid.Row="1"
Width="{Binding ActualWidth, ElementName=GridTrackParent}"
Height="{Binding ActualHeight, ElementName=GridTrackParent}">
<Track.DecreaseRepeatButton>
<RepeatButton Visibility="Hidden" Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource StyleThumbSlider}" />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Visibility="Hidden" Command="Slider.IncreaseLarge" />
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</Border>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleColorSelector"
TargetType="{x:Type controls:ColorSelector}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="504" />
<Setter Property="Height" Value="232" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ColorSelector}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<DockPanel Margin="{TemplateBinding Padding}">
<Border DockPanel.Dock="Left"
SnapsToDevicePixels="True"
Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
BorderThickness="1"
BorderBrush="#FF000000"
Background="#FFFFFFFF">
<Grid x:Name="PART_Selector"
Margin="1"
SnapsToDevicePixels="True" />
</Border>
<Slider DockPanel.Dock="Left"
Margin="8,0"
Height="24"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
Background="{Binding Background, ElementName=PART_SliderHue}"
Minimum="{Binding Minimum, ElementName=PART_SliderHue}"
Maximum="{Binding Maximum, ElementName=PART_SliderHue}"
Value="{Binding Value, ElementName=PART_SliderHue}">
<Slider.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
</Slider.LayoutTransform>
</Slider>
<DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="28" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Alpha:" />
<Slider x:Name="PART_SliderAlpha"
Grid.Row="0" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="0" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderAlpha, StringFormat=##0}" />
<TextBlock Grid.Row="2" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Hue:" />
<Slider x:Name="PART_SliderHue"
Grid.Row="2" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="360" />
<TextBlock Grid.Row="2" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderHue, StringFormat=##0}" />
<TextBlock Grid.Row="4" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Sat:" />
<Slider x:Name="PART_SliderSaturation"
Grid.Row="4" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="1" />
<TextBlock Grid.Row="4" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderSaturation, StringFormat=0.00}" />
<TextBlock Grid.Row="6" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Value:" />
<Slider x:Name="PART_SliderValue"
Grid.Row="6" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="1" />
<TextBlock Grid.Row="6" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderValue, StringFormat=0.00}" />
<TextBlock Grid.Row="8" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Red:" />
<Slider x:Name="PART_SliderRed"
Grid.Row="8" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="8" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderRed, StringFormat=000}" />
<TextBlock Grid.Row="10" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Green:" />
<Slider x:Name="PART_SliderGreen"
Grid.Row="10" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="10" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderGreen, StringFormat=000}" />
<TextBlock Grid.Row="12" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Blue:" />
<Slider x:Name="PART_SliderBlue"
Grid.Row="12" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="12" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderBlue, StringFormat=000}" />
</Grid>
<Border HorizontalAlignment="Stretch"
Margin="0,0,0,4"
SnapsToDevicePixels="True"
BorderThickness="1"
BorderBrush="#FF000000"
Background="#FFFFFFFF">
<Border Margin="1"
SnapsToDevicePixels="True"
Background="{StaticResource BrushChessboard}">
<Rectangle x:Name="PART_Preview"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
SnapsToDevicePixels="True" />
</Border>
</Border>
</DockPanel>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:ColorSelector}" BasedOn="{StaticResource StyleColorSelector}" />
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,144 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleComboBoxItem"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type ComboBoxItem}">
<Setter Property="Foreground" Value="{StaticResource BrushComboBoxForeground}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource BrushComboBoxHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="ComboBoxToggleButton"
TargetType="{x:Type ToggleButton}">
<Border x:Name="Border"
CornerRadius="0"
Background="{StaticResource BrushComboBoxBackground}"
BorderBrush="{StaticResource BrushComboBoxBorder}"
BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
CornerRadius="0"
Margin="1"
Background="Transparent"
BorderBrush="{StaticResource BrushComboBoxBorder}"
BorderThickness="0,0,1,0" />
<Path x:Name="Arrow"
Grid.Column="1"
Fill="{StaticResource BrushComboBoxForeground}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource BrushComboBoxHover}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox"
TargetType="{x:Type TextBox}">
<Border x:Name="PART_ContentHost"
Focusable="False"
Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="StyleComboBox"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type ComboBox}" >
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Foreground" Value="{StaticResource BrushComboBoxForeground}"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource StyleComboBoxItem}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Focusable="False"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="6,3,26,3"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder"
Background="{StaticResource BrushComboBoxBackgroundPopup}"
BorderThickness="1"
BorderBrush="{StaticResource BrushComboBoxBorder}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsGrouping" Value="True">
<Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="0"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</styles:CachedResourceDictionary>

99
RGBSync+/Styles/Form.xaml Normal file
View File

@ -0,0 +1,99 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleForm"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type controls:Form}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="LabelWidth" Value="112" />
<Setter Property="ElementSpacing" Value="8" />
<Setter Property="RowSpacing" Value="8" />
</Style>
<Style x:Key="StyleLabelForm"
TargetType="Label">
<Setter Property="Foreground" Value="{StaticResource BrushForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Right" />
<!-- DarthAffe 04.08.2017: Quite a botch, but it works ... -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<TextBlock HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleTextBlockForm"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource BrushForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="TextAlignment" Value="Left" />
</Style>
<Style x:Key="StyleListBoxItemForm"
TargetType="ListBoxItem">
<Setter Property="MinWidth" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="0,2" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleListBoxForm"
TargetType="ListBox">
<Setter Property="Focusable" Value="False" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="ItemContainerStyle" Value="{StaticResource StyleListBoxItemForm}" />
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,13 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<Style x:Key="StyleFrameworkElement" TargetType="FrameworkElement">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,93 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/ColorSelector.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleGradientStop"
TargetType="ContentControl">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Width" Value="12" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FFFFFFFF" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type GradientStop}">
<Grid>
<Path Stretch="Fill"
Data="M 0.5,0 L 0,0.25 L 0,1 L 1,1 L 1,0.25 Z"
StrokeThickness="0"
Fill="{StaticResource BrushChessboardSmall}" />
<Path Stretch="Fill"
Data="M 0.5,0 L 0,0.25 L 0,1 L 1,1 L 1,0.25 Z"
Stroke="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=ContentControl}}"
StrokeThickness="{Binding BorderThickness, RelativeSource={RelativeSource AncestorType=ContentControl}}"
Fill="{Binding Background, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding (controls:GradientEditor.IsSelected), RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="BorderBrush" Value="#FF808080" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="StyleGradientEditor"
TargetType="{x:Type controls:GradientEditor}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Height" Value="60" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="GradientStopStyle" Value="{StaticResource StyleGradientStop}" />
<Setter Property="ColorSelectorTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type GradientStop}">
<GroupBox>
<controls:ColorSelector Foreground="#FFFFFFFF" SelectedColor="{Binding Color}" />
</GroupBox>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:GradientEditor}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<DockPanel>
<Border DockPanel.Dock="Bottom"
Height="16">
<Canvas x:Name="PART_Stops"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="Transparent" />
</Border>
<Border Background="{StaticResource BrushChessboard}">
<Canvas x:Name="PART_Gradient"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="Transparent" />
</Border>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:GradientEditor}" BasedOn="{StaticResource StyleGradientEditor}" />
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,35 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleGroupBoxBox"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="GroupBox">
<Setter Property="Foreground" Value="{StaticResource BrushForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="Background" Value="{StaticResource BrushBoxBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushBoxBorder}" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Padding" Value="6,8" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter Margin="{TemplateBinding Padding}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,119 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:buttons="clr-namespace:RGBSyncPlus.Controls"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleImageButton"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type buttons:ImageButton}">
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type buttons:ImageButton}">
<Grid Background="Transparent">
<Image x:Name="ImageNormal" Margin="{TemplateBinding Padding}"
Source="{TemplateBinding Image}" Stretch="Uniform" />
<Image x:Name="ImageHover" Margin="{TemplateBinding Padding}"
Opacity="0"
Source="{TemplateBinding HoverImage}" Stretch="Uniform" />
<Image x:Name="ImagePressed" Margin="{TemplateBinding Padding}"
Opacity="0"
Source="{TemplateBinding PressedImage}" Stretch="Uniform" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetName="ImageHover">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.150" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetName="ImageHover">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.250" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetName="ImagePressed">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.150" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetName="ImagePressed">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.250" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleImageButtonWithOpacity"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type buttons:ImageButton}">
<Setter Property="Opacity" Value="0.66" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type buttons:ImageButton}">
<Grid Background="Transparent">
<Image x:Name="ImageNormal" Margin="{TemplateBinding Padding}"
Source="{TemplateBinding Image}" Stretch="Uniform" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.150" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0.250" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="StyleImageButtonMenu"
BasedOn="{StaticResource StyleImageButton}"
TargetType="{x:Type buttons:ImageButton}">
<Setter Property="Width" Value="180" />
<Setter Property="Height" Value="90" />
<Setter Property="Margin" Value="0,16" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,164 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:converter="clr-namespace:RGBSyncPlus.Converter">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<converter:ScrollOffsetToOpacityMaskConverter x:Key="ScrollOffsetToOpacityMaskConverter" />
<converter:ScrollOffsetToVisibilityConverter x:Key="ScrollOffsetToVisibilityConverter" />
<Style x:Key="ListBoxScrollViewButtonStyle" TargetType="RepeatButton">
<Style.Setters>
<Setter Property="Background" Value="{StaticResource BrushListBoxScrollButtonBackground}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border x:Name="ButtonBorder"
HorizontalAlignment="Center"
Width="80"
Height="30"
BorderThickness="1"
BorderBrush="{StaticResource BrushListBoxScrollButtonBorder}"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BrushListBoxScrollButtonBackgroundHover}" />
</Trigger>
</Style.Triggers>
</Style>
<ControlTemplate x:Key="ListBoxTemplate" TargetType="ListBox">
<Grid>
<ScrollViewer x:Name="ScrollViewer" CanContentScroll="False" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden">
<ScrollViewer.OpacityMask>
<MultiBinding Converter="{StaticResource ScrollOffsetToOpacityMaskConverter}" ConverterParameter="30">
<Binding ElementName="ScrollViewer" Path="VerticalOffset" />
<Binding ElementName="ScrollViewer" Path="ScrollableHeight" />
<Binding ElementName="ScrollViewer" Path="ActualHeight" />
</MultiBinding>
</ScrollViewer.OpacityMask>
<ItemsPresenter />
</ScrollViewer>
<DockPanel LastChildFill="False">
<RepeatButton DockPanel.Dock="Top" Style="{StaticResource ListBoxScrollViewButtonStyle}"
Command="{x:Static ScrollBar.LineUpCommand}" CommandTarget="{Binding ElementName=ScrollViewer}">
<RepeatButton.Visibility>
<MultiBinding Converter="{StaticResource ScrollOffsetToVisibilityConverter}" ConverterParameter="Top">
<Binding ElementName="ScrollViewer" Path="VerticalOffset"/>
<Binding ElementName="ScrollViewer" Path="ScrollableHeight"/>
</MultiBinding>
</RepeatButton.Visibility>
<RepeatButton.Content>
<Image Source="/RGBSync+;component/Resources/arrow_up.png" Stretch="Uniform" />
</RepeatButton.Content>
</RepeatButton>
<RepeatButton DockPanel.Dock="Bottom" Style="{StaticResource ListBoxScrollViewButtonStyle}"
Command="{x:Static ScrollBar.LineDownCommand}" CommandTarget="{Binding ElementName=ScrollViewer}">
<RepeatButton.Visibility>
<MultiBinding Converter="{StaticResource ScrollOffsetToVisibilityConverter}" ConverterParameter="Bottom">
<Binding ElementName="ScrollViewer" Path="VerticalOffset"/>
<Binding ElementName="ScrollViewer" Path="ScrollableHeight"/>
</MultiBinding>
</RepeatButton.Visibility>
<RepeatButton.Content>
<Image Source="/RGBSync+;component/Resources/arrow_down.png" Stretch="Uniform" />
</RepeatButton.Content>
</RepeatButton>
</DockPanel>
</Grid>
</ControlTemplate>
<Style x:Key="StyleListBoxItemContainer"
TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ItemBorder"
HorizontalAlignment="Stretch"
BorderThickness="0"
BorderBrush="Transparent"
Background="{StaticResource BrushListBoxItemBackground}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ItemBorder"
Storyboard.TargetProperty="Background.Color"
To="{StaticResource ColorListBoxItemBackgroundHover}"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ItemBorder"
Storyboard.TargetProperty="Background.Color"
Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ItemBorder"
Storyboard.TargetProperty="Background.Color"
To="{StaticResource ColorListBoxItemBackgroundSelected}"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ItemBorder"
Storyboard.TargetProperty="Background.Color"
Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleListBox"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="ListBox">
<Setter Property="Foreground" Value="{StaticResource BrushButtonForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="Background" Value="{StaticResource BrushButtonBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushButtonBorder}" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Padding" Value="4,2" />
<Setter Property="ItemContainerStyle" Value="{StaticResource StyleListBoxItemContainer}" />
<Setter Property="Template" Value="{StaticResource ListBoxTemplate}" />
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,181 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:controls="clr-namespace:Transitionals.Controls;assembly=Transitionals"
xmlns:transitions="clr-namespace:Transitionals.Transitions;assembly=Transitionals">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<transitions:FadeTransition x:Key="TransitionFade" Duration="0:0:0.200" />
<Style x:Key="StyleTabControlNavigation"
TargetType="TabControl">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Margin" Value="0,-72,0,0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<!-- DarthAffe 04.08.2017: The TabControl is a shitty one to style - if unused parts are removed it throws exceptions ... -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0" />
<ColumnDefinition x:Name="ColumnDefinition1" Width="0" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto" />
<RowDefinition x:Name="RowDefinition1" Height="*" />
</Grid.RowDefinitions>
<TabPanel x:Name="HeaderPanel"
Grid.Row="0"
Grid.Column="0"
Margin="82,2,2,0"
Panel.ZIndex="1"
IsItemsHost="true"
KeyboardNavigation.TabIndex="1" />
<Border x:Name="ContentPanel"
Grid.Column="0"
Grid.Row="1"
Margin="4"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2"
KeyboardNavigation.TabNavigation="Local">
<controls:TransitionElement x:Name="PART_SelectedContentHost"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Transition="{StaticResource TransitionFade}"
Content="{TemplateBinding SelectedContent}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1" />
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0" />
<Setter Property="Height" TargetName="RowDefinition0" Value="*" />
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto" />
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2" />
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0" />
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0" />
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0" />
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1" />
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto" />
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*" />
<Setter Property="Height" TargetName="RowDefinition0" Value="*" />
<Setter Property="Height" TargetName="RowDefinition1" Value="0" />
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2" />
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0" />
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0" />
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1" />
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0" />
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*" />
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto" />
<Setter Property="Height" TargetName="RowDefinition0" Value="*" />
<Setter Property="Height" TargetName="RowDefinition1" Value="0" />
<Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleTabItemNavigation"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="TabItem">
<Setter Property="Height" Value="72" />
<Setter Property="FontSize" Value="{StaticResource FontSizeNavigation}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel Decorative" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Margin="8,0"
Padding="4"
IsHitTestVisible="True"
BorderThickness="0"
Background="Transparent">
<Grid>
<TextBlock x:Name="TxtBlurred"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontWeight="Black"
Opacity="0"
Foreground="{StaticResource BrushNavigationItemBlur}"
Text="{TemplateBinding Header}">
<TextBlock.Effect>
<BlurEffect Radius="{StaticResource DoubleNavigationBlurRadius}" />
</TextBlock.Effect>
</TextBlock>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="{StaticResource BrushNavigationItem}"
Text="{TemplateBinding Header}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Margin" Value="80,0,0,0" />
</DataTrigger>-->
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetName="TxtBlurred">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.150" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetName="TxtBlurred">
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0.250" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetName="TxtBlurred">
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.150" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetName="TxtBlurred">
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0.250" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style BasedOn="{StaticResource StyleTabItemNavigation}" TargetType="TabItem" />
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,31 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:attached="clr-namespace:RGBSyncPlus.Attached">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleSlider"
BasedOn="{StaticResource {x:Type Slider}}"
TargetType="Slider">
<!-- ReSharper disable Xaml.RedundantStyledValue - -->
<Setter Property="attached:SliderValue.IsShown" Value="True" />
<Setter Property="attached:SliderValue.Background" Value="{StaticResource BrushTooltipBackground}" />
<Setter Property="attached:SliderValue.BorderBrush" Value="{StaticResource BrushTooltipBorder}" />
<Setter Property="attached:SliderValue.Foreground" Value="{StaticResource BrushTooltipForeground}" />
<Setter Property="attached:SliderValue.FontSize" Value="{StaticResource FontSizeTooltip}" />
<Setter Property="attached:SliderValue.Font" Value="pack://application:,,,/Resources/#Cinzel" />
<!-- ReSharper restore Xaml.RedundantStyledValue -->
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.2" />
</Trigger>
</Style.Triggers>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,45 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleTextBox"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="TextBox">
<Setter Property="Foreground" Value="{StaticResource BrushTextBoxForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="Background" Value="{StaticResource BrushTextBoxBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorder}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border Name="Border"
Padding="2"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderHover}" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderFocused}" />
</Trigger>
</Style.Triggers>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,75 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:presentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options">
<!-- ### Colors ### -->
<Color x:Key="ColorGainsboro">#FFDCDCDC</Color>
<Color x:Key="ColorBuckinghamGray">#FF2A2A2A</Color>
<Color x:Key="ColorBuckinghamGrayTransparent">#B82A2A2A</Color>
<Color x:Key="ColorJetBlack">#111111</Color>
<Color x:Key="ColorJetBlackTransparent">#B8111111</Color>
<Color x:Key="ColorJetBlackSuperTransparent">#60111111</Color>
<Color x:Key="ColorBlackTransparent">#50000000</Color>
<Color x:Key="ColorBananaYellow">#FFE135</Color>
<!-- ### Brushes ### -->
<SolidColorBrush x:Key="BrushBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<SolidColorBrush x:Key="BrushForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<!-- Window -->
<SolidColorBrush x:Key="BrushWindowBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorBlackTransparent}" />
<SolidColorBrush x:Key="BrushWindowBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<!-- Box -->
<SolidColorBrush x:Key="BrushBoxBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushBoxBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackSuperTransparent}" />
<!-- ToolTip -->
<SolidColorBrush x:Key="BrushTooltipForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushTooltipBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<SolidColorBrush x:Key="BrushTooltipBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<!-- ComboBox -->
<SolidColorBrush x:Key="BrushComboBoxForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushComboBoxBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorBuckinghamGrayTransparent}" />
<SolidColorBrush x:Key="BrushComboBoxBackgroundPopup" presentationOptions:Freeze="True" Color="{StaticResource ColorBuckinghamGray}" />
<SolidColorBrush x:Key="BrushComboBoxBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushComboBoxHover" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<SolidColorBrush x:Key="BrushComboBoxBackgroundGroupHeader" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackSuperTransparent}" />
<!-- Button -->
<SolidColorBrush x:Key="BrushButtonForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushButtonBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorBuckinghamGrayTransparent}" />
<SolidColorBrush x:Key="BrushButtonBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushButtonHover" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<!-- ListBox -->
<SolidColorBrush x:Key="BrushListBoxForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushListBoxScrollButtonBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackSuperTransparent}" />
<SolidColorBrush x:Key="BrushListBoxScrollButtonBackgroundHover" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushListBoxScrollButtonBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushListBoxItemBackground" presentationOptions:Freeze="True" Color="#00111111" />
<Color x:Key="ColorListBoxItemBackgroundHover">#60111111</Color>
<Color x:Key="ColorListBoxItemBackgroundSelected">#B8111111</Color>
<!-- TextBox -->
<SolidColorBrush x:Key="BrushTextBoxForeground" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushTextBoxBackground" presentationOptions:Freeze="True" Color="{StaticResource ColorBuckinghamGrayTransparent}" />
<SolidColorBrush x:Key="BrushTextBoxBorder" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlackTransparent}" />
<SolidColorBrush x:Key="BrushTextBoxBorderHover" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<SolidColorBrush x:Key="BrushTextBoxBorderFocused" presentationOptions:Freeze="True" Color="{StaticResource ColorJetBlack}" />
<!-- Navigation -->
<SolidColorBrush x:Key="BrushNavigationItem" presentationOptions:Freeze="True" Color="{StaticResource ColorGainsboro}" />
<SolidColorBrush x:Key="BrushNavigationItemBlur" presentationOptions:Freeze="True" Color="{StaticResource ColorBananaYellow}" />
<!-- ### Border'n'stuff ### -->
<sys:Double x:Key="DoubleNavigationBlurRadius">40</sys:Double>
<!-- ### Fonts ### -->
<sys:Double x:Key="FontSizeDefault">14</sys:Double>
<sys:Double x:Key="FontSizeTooltip">14</sys:Double>
<sys:Double x:Key="FontSizeNavigation">22</sys:Double>
</ResourceDictionary>

View File

@ -0,0 +1,31 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/FrameworkElement.xaml" />
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Theme.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleToolTip"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type ToolTip}">
<Setter Property="Foreground" Value="{StaticResource BrushTooltipForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeTooltip}" />
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Cinzel" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Border BorderThickness="1"
BorderBrush="{StaticResource BrushTooltipBorder}"
Background="{StaticResource BrushTooltipBackground}">
<ContentPresenter Margin="6,4" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,183 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using GongSolutions.Wpf.DragDrop;
using RGB.NET.Core;
using RGBSyncPlus.Helper;
using RGBSyncPlus.Model;
namespace RGBSyncPlus.UI
{
public sealed class ConfigurationViewModel : AbstractBindable, IDropTarget
{
#region Properties & Fields
public Version Version => Assembly.GetEntryAssembly().GetName().Version;
public double UpdateRate
{
get => 1.0 / ApplicationManager.Instance.UpdateTrigger.UpdateFrequency;
set
{
double val = MathHelper.Clamp(value, 1, 100);
ApplicationManager.Instance.Settings.UpdateRate = val;
ApplicationManager.Instance.UpdateTrigger.UpdateFrequency = 1.0 / val;
OnPropertyChanged();
}
}
private ObservableCollection<SyncGroup> _syncGroups;
public ObservableCollection<SyncGroup> SyncGroups
{
get => _syncGroups;
set => SetProperty(ref _syncGroups, value);
}
private SyncGroup _selectedSyncGroup;
public SyncGroup SelectedSyncGroup
{
get => _selectedSyncGroup;
set
{
if (SetProperty(ref _selectedSyncGroup, value))
UpdateLedLists();
}
}
private ListCollectionView _availableSyncLeds;
public ListCollectionView AvailableSyncLeds
{
get => _availableSyncLeds;
set => SetProperty(ref _availableSyncLeds, value);
}
private ListCollectionView _availableLeds;
public ListCollectionView AvailableLeds
{
get => _availableLeds;
set => SetProperty(ref _availableLeds, value);
}
private ListCollectionView _synchronizedLeds;
public ListCollectionView SynchronizedLeds
{
get => _synchronizedLeds;
set => SetProperty(ref _synchronizedLeds, value);
}
#endregion
#region Commands
private ActionCommand _openHomepageCommand;
public ActionCommand OpenHomepageCommand => _openHomepageCommand ?? (_openHomepageCommand = new ActionCommand(OpenHomepage));
private ActionCommand _addSyncGroupCommand;
public ActionCommand AddSyncGroupCommand => _addSyncGroupCommand ?? (_addSyncGroupCommand = new ActionCommand(AddSyncGroup));
private ActionCommand<SyncGroup> _removeSyncGroupCommand;
public ActionCommand<SyncGroup> RemoveSyncGroupCommand => _removeSyncGroupCommand ?? (_removeSyncGroupCommand = new ActionCommand<SyncGroup>(RemoveSyncGroup));
#endregion
#region Constructors
public ConfigurationViewModel()
{
SyncGroups = new ObservableCollection<SyncGroup>(ApplicationManager.Instance.Settings.SyncGroups);
AvailableSyncLeds = GetGroupedLedList(RGBSurface.Instance.Leds.Where(x => x.Device.DeviceInfo.SupportsSyncBack));
OnPropertyChanged(nameof(AvailableSyncLeds));
}
#endregion
#region Methods
private ListCollectionView GetGroupedLedList(IEnumerable<Led> leds) => GetGroupedLedList(leds.Select(led => new SyncLed(led)).ToList());
private ListCollectionView GetGroupedLedList(IList syncLeds)
{
ListCollectionView collectionView = new ListCollectionView(syncLeds);
collectionView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(SyncLed.Device)));
collectionView.SortDescriptions.Add(new SortDescription(nameof(SyncLed.Device), ListSortDirection.Ascending));
collectionView.SortDescriptions.Add(new SortDescription(nameof(SyncLed.LedId), ListSortDirection.Ascending));
collectionView.Refresh();
return collectionView;
}
private void UpdateLedLists()
{
SynchronizedLeds = GetGroupedLedList(SelectedSyncGroup.Leds);
OnPropertyChanged(nameof(SynchronizedLeds));
AvailableLeds = GetGroupedLedList(RGBSurface.Instance.Leds.Where(led => !SelectedSyncGroup.Leds.Any(sc => (sc.LedId == led.Id) && (sc.Device == led.Device.GetDeviceName()))));
OnPropertyChanged(nameof(AvailableLeds));
}
private void OpenHomepage() => Process.Start("https://github.com/DarthAffe/RGBSyncPlus");
private void AddSyncGroup()
{
SyncGroup syncGroup = new SyncGroup();
SyncGroups.Add(syncGroup);
ApplicationManager.Instance.AddSyncGroup(syncGroup);
}
private void RemoveSyncGroup(SyncGroup syncGroup)
{
if (syncGroup == null) return;
if (MessageBox.Show($"Are you sure that you want to delete the group '{syncGroup.DisplayName}'", "Remove Sync-Group", MessageBoxButton.YesNo) == MessageBoxResult.No)
return;
SyncGroups.Remove(syncGroup);
ApplicationManager.Instance.RemoveSyncGroup(syncGroup);
}
void IDropTarget.DragOver(IDropInfo dropInfo)
{
if ((dropInfo.Data is SyncLed || dropInfo.Data is IEnumerable<SyncLed>) && (dropInfo.TargetCollection is ListCollectionView))
{
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
dropInfo.Effects = DragDropEffects.Copy;
}
}
void IDropTarget.Drop(IDropInfo dropInfo)
{
if (!(dropInfo.TargetCollection is ListCollectionView targetList)) return;
//HACK DarthAffe 04.06.2018: Super ugly hack - I've no idea how to do this correctly ...
ListCollectionView sourceList = targetList == AvailableLeds ? SynchronizedLeds : AvailableLeds;
if (dropInfo.Data is SyncLed syncLed)
{
targetList.AddNewItem(syncLed);
sourceList.Remove(syncLed);
targetList.CommitNew();
sourceList.CommitEdit();
}
else if (dropInfo.Data is IEnumerable<SyncLed> syncLeds)
{
foreach (SyncLed led in syncLeds)
{
targetList.AddNewItem(led);
sourceList.Remove(led);
}
targetList.CommitNew();
sourceList.CommitEdit();
}
}
#endregion
}
}

View File

@ -0,0 +1,250 @@
<controls:BlurredDecorationWindow x:Class="RGBSyncPlus.UI.ConfigurationWindow"
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:core="clr-namespace:RGB.NET.Core;assembly=RGB.NET.Core"
xmlns:ui="clr-namespace:RGBSyncPlus.UI"
xmlns:controls="clr-namespace:RGBSyncPlus.Controls"
xmlns:styles="clr-namespace:RGBSyncPlus.Styles"
xmlns:attached="clr-namespace:RGBSyncPlus.Attached"
xmlns:helper="clr-namespace:RGBSyncPlus.Helper"
xmlns:dd="urn:gong-wpf-dragdrop"
mc:Ignorable="d"
Title="RGBSync+ # Configuration"
Icon="pack://application:,,,/RGBSync+;component/Resources/argebee.ico"
IconCommand="{Binding OpenHomepageCommand}"
Width="1280" Height="720"
Closed="ConfigurationWindow_OnClosed">
<controls:BlurredDecorationWindow.Resources>
<styles:CachedResourceDictionary>
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/RGBSync+;component/Styles/Navigation.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
</styles:CachedResourceDictionary>
</controls:BlurredDecorationWindow.Resources>
<controls:BlurredDecorationWindow.DataContext>
<ui:ConfigurationViewModel />
</controls:BlurredDecorationWindow.DataContext>
<TabControl Style="{StaticResource StyleTabControlNavigation}">
<TabItem Header="Sync-Groups">
<AdornerDecorator>
<DockPanel LastChildFill="True">
<GroupBox DockPanel.Dock="Left" Width="260">
<DockPanel VerticalAlignment="Top">
<Button DockPanel.Dock="Bottom"
HorizontalAlignment="Center"
Margin="8"
Content="New Sync-Group"
Command="{Binding AddSyncGroupCommand}" />
<ListBox ItemsSource="{Binding SyncGroups}"
SelectedItem="{Binding SelectedSyncGroup}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
ToolTip="Remove"
Command="{Binding DataContext.RemoveSyncGroupCommand, RelativeSource={RelativeSource AncestorType={x:Type controls:BlurredDecorationWindow}}}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBoxItem}}">
<Image Source="/RGBSync+;component/Resources/close.png" />
</Button>
<TextBlock Grid.Column="1" Margin="4" Text="{Binding DisplayName}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</GroupBox>
<DockPanel Margin="8,0,0,0">
<GroupBox DockPanel.Dock="Top">
<Grid>
<Border HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="16"
Visibility="{Binding SelectedSyncGroup, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=True}">
<TextBlock Text="No Sync-Group selected ..." />
</Border>
<Border Visibility="{Binding SelectedSyncGroup, Converter={StaticResource NullToVisibilityConverter}}">
<Border.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
</Border.Resources>
<controls:Form DockPanel.Dock="Top">
<Label controls:Form.IsLabel="True"
Content="Name:" />
<TextBox controls:Form.Fill="True"
Text="{Binding SelectedSyncGroup.Name, UpdateSourceTrigger=PropertyChanged}" />
<Label controls:Form.IsLabel="True"
Content="Sync-LED:" />
<ComboBox controls:Form.Fill="True"
ItemsSource="{Binding AvailableSyncLeds}"
SelectedItem="{Binding SelectedSyncGroup.SyncLed}">
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="{StaticResource BrushComboBoxBackgroundGroupHeader}">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Left"
FontWeight="Bold"
Text="{Binding Name}" />
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding LedId}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:Form>
</Border>
</Grid>
</GroupBox>
<Grid Margin="0,8,0,0"
Visibility="{Binding SelectedSyncGroup, Converter={StaticResource NullToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<GroupStyle x:Key="StyleListBoxGroup">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="0,8,0,0"
FontWeight="Bold"
Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<DataTemplate x:Key="DataTemplateListBoxItem">
<TextBlock Text="{Binding LedId}"/>
</DataTemplate>
</Grid.Resources>
<GroupBox Grid.Column="0">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Center"
Margin="0,0,0,8"
FontWeight="Bold"
Text="Available LEDS" />
<ListBox SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
ItemTemplate="{StaticResource DataTemplateListBoxItem}"
ItemsSource="{Binding AvailableLeds}">
<ListBox.GroupStyle>
<StaticResource ResourceKey="StyleListBoxGroup" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
</GroupBox>
<GroupBox Grid.Column="2">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Center"
Margin="0,0,0,8"
FontWeight="Bold"
Text="Synchronized LEDS" />
<ListBox SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
ItemTemplate="{StaticResource DataTemplateListBoxItem}"
ItemsSource="{Binding SynchronizedLeds}">
<ListBox.GroupStyle>
<StaticResource ResourceKey="StyleListBoxGroup" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
</GroupBox>
</Grid>
</DockPanel>
</DockPanel>
</AdornerDecorator>
</TabItem>
<TabItem Header="Settings">
<AdornerDecorator>
<GroupBox VerticalAlignment="Top">
<StackPanel Orientation="Vertical">
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:Form Grid.Column="0">
<Label controls:Form.IsLabel="True"
Content="Version:" />
<TextBlock Text="{Binding Version}" />
<Label controls:Form.IsLabel="True"
Content="Update-Rate" />
<Slider Minimum="1" Maximum="100" controls:Form.Fill="True" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight"
Value="{Binding UpdateRate}"
attached:SliderValue.Unit="UPS"
ToolTip="Defines how fast the data is updated.&#x0a;Low values can reduce CPU-usage but might cause stuttering." />
<Label controls:Form.LineBreaks="1" controls:Form.IsLabel="True" Content="Devices:" />
</controls:Form>
</Grid>
<ItemsControl VerticalAlignment="Top" HorizontalAlignment="Left" Margin="120,-22,0,0" ItemsSource="{Binding Source={x:Static core:RGBSurface.Instance}, Path=Devices}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource StyleTextBlockForm}">
<TextBlock.Text>
<MultiBinding StringFormat="> {0} {1} ({2})">
<Binding Path="DeviceInfo.Manufacturer" />
<Binding Path="DeviceInfo.Model" />
<Binding Path="DeviceInfo.DeviceType" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</GroupBox>
</AdornerDecorator>
</TabItem>
</TabControl>
</controls:BlurredDecorationWindow>

View File

@ -0,0 +1,16 @@
using System;
using RGBSyncPlus.Controls;
namespace RGBSyncPlus.UI
{
public partial class ConfigurationWindow : BlurredDecorationWindow
{
public ConfigurationWindow() => InitializeComponent();
//DarthAffe 07.02.2018: This prevents the applicaiton from not shutting down and crashing afterwards if 'close' is selected in the taskbar-context-menu
private void ConfigurationWindow_OnClosed(object sender, EventArgs e)
{
ApplicationManager.Instance.ExitCommand.Execute(null);
}
}
}