From 3f11919600a5338c44f848d19a45b76b02815e0b Mon Sep 17 00:00:00 2001 From: radj307 Date: Tue, 22 Feb 2022 13:59:44 -0500 Subject: [PATCH] begin adding JSON serialization capabilities to ColorSchemes --- UIComposites/ColorBinding.cs | 13 +++ UIComposites/ColorBindingBase.cs | 54 +++++++++++++ UIComposites/ColorScheme.cs | 133 ++++++------------------------- UIComposites/ColorSchemeList.cs | 30 +++++++ UIComposites/IColorBinding.cs | 30 +++++++ UIComposites/IColorSchemeFile.cs | 84 +++++++++++++++++++ UIComposites/JSON.cs | 18 +++++ VolumeControl/Program.cs | 12 ++- 8 files changed, 263 insertions(+), 111 deletions(-) create mode 100644 UIComposites/ColorBinding.cs create mode 100644 UIComposites/ColorBindingBase.cs create mode 100644 UIComposites/ColorSchemeList.cs create mode 100644 UIComposites/IColorBinding.cs create mode 100644 UIComposites/IColorSchemeFile.cs create mode 100644 UIComposites/JSON.cs diff --git a/UIComposites/ColorBinding.cs b/UIComposites/ColorBinding.cs new file mode 100644 index 000000000..b0a6cc60b --- /dev/null +++ b/UIComposites/ColorBinding.cs @@ -0,0 +1,13 @@ +//using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify; + +namespace UIComposites +{ + public class ColorBinding : ColorBindingBase where T : Control + { + public ColorBinding(Color? fg = null, Color? bg = null) : base(fg, bg) {} + public ColorBinding() {} + + public override bool AppliesToControl(Control type) + => type is T; + } +} diff --git a/UIComposites/ColorBindingBase.cs b/UIComposites/ColorBindingBase.cs new file mode 100644 index 000000000..30c0615f4 --- /dev/null +++ b/UIComposites/ColorBindingBase.cs @@ -0,0 +1,54 @@ +//using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify; + +namespace UIComposites +{ + public class ColorBindingBase : IColorBinding + { + protected ColorBindingBase((Color, bool) fg, (Color, bool) bg) + { + _fg = fg.Item1; + _fgEnabled = fg.Item2; + _bg = bg.Item1; + _bgEnabled = bg.Item2; + } + protected ColorBindingBase(Color? fg = null, Color? bg = null) + { + _fg = fg ?? Color.Transparent; + _fgEnabled = fg != null; + _bg = bg ?? Color.Transparent; + _bgEnabled = bg != null; + } + protected ColorBindingBase() + { + _fg = Color.Transparent; + _fgEnabled = false; + _bg = Color.Transparent; + _bgEnabled = false; + } + + protected Color _fg, _bg; + protected bool _fgEnabled, _bgEnabled; + + Color IColorBinding.Foreground { get => _fg; set => _fg = value; } + Color IColorBinding.Background { get => _bg; set => _bg = value; } + bool IColorBinding.EnableForeground { get => _fgEnabled; set => _fgEnabled = value; } + bool IColorBinding.EnableBackground { get => _bgEnabled; set => _bgEnabled = value; } + + public Color GetForeColor() => _fg; + public bool GetForeColorEnabled() => _fgEnabled; + public Color GetBackColor() => _bg; + public bool GetBackColorEnabled() => _bgEnabled; + + virtual public bool AppliesToControl(Control type) + { + throw new NotImplementedException("Cannot instantiate ColorBindingBase object."); + } + + public Form ApplyToSingle(Form frm) + { + frm.ForeColor = _fg; + frm.BackColor = _bg; + return frm; + } + } +} diff --git a/UIComposites/ColorScheme.cs b/UIComposites/ColorScheme.cs index e8f0a91bf..dda16d80f 100644 --- a/UIComposites/ColorScheme.cs +++ b/UIComposites/ColorScheme.cs @@ -1,113 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -//using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify; +using System.Text.Json; namespace UIComposites { - public interface IColorBinding + public partial class ColorScheme : IColorSchemeFile { - public Color Foreground { get; set; } - public Color Background { get; set; } - public bool EnableForeground { get; set; } - public bool EnableBackground { get; set; } - - /// - /// Predicate function that determines whether or not this binding may apply to the given control type. - /// - /// Control type to test. - /// bool - public bool AppliesToControl(Control type); - /// - /// Apply this color binding to the given control reference. - /// Does NOT recurse. - /// - /// Control Ref - public Control ApplyTo(Control ctrl) - { - ctrl.ForeColor = Foreground; - ctrl.BackColor = Background; - return ctrl; - } - } - - public class ColorBindingBase : IColorBinding - { - protected ColorBindingBase((Color, bool) fg, (Color, bool) bg) - { - _fg = fg.Item1; - _fgEnabled = fg.Item2; - _bg = bg.Item1; - _bgEnabled = bg.Item2; - } - protected ColorBindingBase(Color? fg = null, Color? bg = null) - { - _fg = fg ?? Color.Transparent; - _fgEnabled = fg != null; - _bg = bg ?? Color.Transparent; - _bgEnabled = bg != null; - } - - protected Color _fg, _bg; - protected bool _fgEnabled, _bgEnabled; - - Color IColorBinding.Foreground { get => _fg; set => _fg = value; } - Color IColorBinding.Background { get => _bg; set => _bg = value; } - bool IColorBinding.EnableForeground { get => _fgEnabled; set => _fgEnabled = value; } - bool IColorBinding.EnableBackground { get => _bgEnabled; set => _bgEnabled = value; } - - public Color GetForeColor() => _fg; - public bool GetForeColorEnabled() => _fgEnabled; - public Color GetBackColor() => _bg; - public bool GetBackColorEnabled() => _bgEnabled; - - virtual public bool AppliesToControl(Control type) - { - throw new NotImplementedException("Cannot instantiate ColorBindingBase object."); - } - - public Form ApplyToSingle(Form frm) - { - frm.ForeColor = _fg; - frm.BackColor = _bg; - return frm; - } - } - - public class DefaultColorBinding : ColorBindingBase - { - public DefaultColorBinding(Color? fg = null, Color? bg = null, List? exclude = null) : base(fg, bg) - { - excludeControls = exclude ?? new(); - } - - private readonly List excludeControls; - - public override bool AppliesToControl(Control type) - { - foreach (Type t in excludeControls) - { - if (type.GetType() == t) - return false; - } - return true; - } - } - - public class ColorBinding : ColorBindingBase where T : Control - { - public ColorBinding(Color? fg, Color? bg) : base(fg, bg) {} - - public override bool AppliesToControl(Control type) - => type is T; - } - - - public partial class ColorScheme - { - public ColorScheme(DefaultColorBinding defaultColors, List colors) + public ColorScheme(ColorBinding defaultColors, List colors) { Theme = colors; Default = defaultColors; @@ -120,9 +17,13 @@ public ColorScheme() BorderHighlight = new(); } + public ColorBinding Default; + public ColorBinding BorderHighlight; public List Theme; - public DefaultColorBinding Default; - public DefaultColorBinding BorderHighlight; + + public IColorBinding Primary { get => this.Default; set => this.Default = (ColorBinding)value; } + public IColorBinding Secondary { get => this.BorderHighlight; set => this.BorderHighlight = (ColorBinding)value; } + public List Components { get => this.Theme; set => this.Theme = value; } private IColorBinding GetApplicableColor(Control type) { @@ -135,7 +36,7 @@ private IColorBinding GetApplicableColor(Control type) } return Default; } - + public void ApplyTo(Control.ControlCollection controls) { foreach (Control ctrl in controls) @@ -145,5 +46,19 @@ public void ApplyTo(Control.ControlCollection controls) ApplyTo(ctrl.Controls); } } + + public static ColorScheme? LoadFromFile(string path) + { + return JSON.Read(path, new JsonSerializerOptions() + { + Converters = + { + new InterfaceConverterFactory(typeof(ColorBinding), typeof(IColorBinding)), + new IListInterfaceConverterFactory(typeof(IColorBinding)) + } + }); + } + public void SaveToFile(string path) => JSON.Write(path, this); + public static void SaveToFile(ColorScheme scheme, string path) => JSON.Write(path, scheme); } } diff --git a/UIComposites/ColorSchemeList.cs b/UIComposites/ColorSchemeList.cs new file mode 100644 index 000000000..0097e2ec8 --- /dev/null +++ b/UIComposites/ColorSchemeList.cs @@ -0,0 +1,30 @@ +namespace UIComposites +{ + public class ColorSchemeList + { + public ColorSchemeList(string dir) + { + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + string[] filenames = Directory.GetFiles(dir, "*.json"); + + foreach (string file in filenames) + { + var scheme = ColorScheme.LoadFromFile(file); + if (scheme != null) + Schemes.Add(Path.GetFileNameWithoutExtension(file), scheme); + } + } + + public Dictionary Schemes = new(); + + public ColorScheme? GetWithName(string schemeName, StringComparison strcomp = StringComparison.Ordinal) + { + foreach (KeyValuePair entry in Schemes) + if (entry.Key.Equals(schemeName, strcomp)) + return entry.Value; + return null; + } + } +} diff --git a/UIComposites/IColorBinding.cs b/UIComposites/IColorBinding.cs new file mode 100644 index 000000000..1ee28ab19 --- /dev/null +++ b/UIComposites/IColorBinding.cs @@ -0,0 +1,30 @@ +//using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify; + +namespace UIComposites +{ + public interface IColorBinding + { + public Color Foreground { get; set; } + public Color Background { get; set; } + public bool EnableForeground { get; set; } + public bool EnableBackground { get; set; } + + /// + /// Predicate function that determines whether or not this binding may apply to the given control type. + /// + /// Control type to test. + /// bool + public bool AppliesToControl(Control type); + /// + /// Apply this color binding to the given control reference. + /// Does NOT recurse. + /// + /// Control Ref + public Control ApplyTo(Control ctrl) + { + ctrl.ForeColor = Foreground; + ctrl.BackColor = Background; + return ctrl; + } + } +} diff --git a/UIComposites/IColorSchemeFile.cs b/UIComposites/IColorSchemeFile.cs new file mode 100644 index 000000000..a3ac354c9 --- /dev/null +++ b/UIComposites/IColorSchemeFile.cs @@ -0,0 +1,84 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace UIComposites +{ + public class ColorBindingConverter : JsonConverter where M : class, I + { + public override I? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize(ref reader, options); + } + + public override void Write(Utf8JsonWriter writer, I value, JsonSerializerOptions options) { } + } + public class ListConverter : JsonConverter> + { + public override IList Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize>(ref reader, options); + } + + public override void Write(Utf8JsonWriter writer, IList value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + public class IListInterfaceConverterFactory : JsonConverterFactory + { + public IListInterfaceConverterFactory(Type interfaceType) + { + this.InterfaceType = interfaceType; + } + + public Type InterfaceType { get; } + + public override bool CanConvert(Type typeToConvert) + { + if (typeToConvert.Equals(typeof(IList<>).MakeGenericType(this.InterfaceType)) + && typeToConvert.GenericTypeArguments[0].Equals(this.InterfaceType)) + { + return true; + } + + return false; + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + return (JsonConverter)Activator.CreateInstance( + typeof(ListConverter<>).MakeGenericType(this.InterfaceType)); + } + } + public class InterfaceConverterFactory : JsonConverterFactory + { + public InterfaceConverterFactory(Type concrete, Type interfaceType) + { + this.ConcreteType = concrete; + this.InterfaceType = interfaceType; + } + + public Type ConcreteType { get; } + public Type InterfaceType { get; } + + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert == this.InterfaceType; + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + var converterType = typeof(ColorBindingConverter<,>).MakeGenericType(this.ConcreteType, this.InterfaceType); + + return (JsonConverter)Activator.CreateInstance(converterType); + } + } + public interface IColorSchemeFile + { + [JsonConverter(typeof(ColorBindingConverter, IColorBinding>))] + public IColorBinding Primary { get; set; } + [JsonConverter(typeof(ColorBindingConverter, IColorBinding>))] + public IColorBinding Secondary { get; set; } + public List Components { get; set; } + } +} diff --git a/UIComposites/JSON.cs b/UIComposites/JSON.cs new file mode 100644 index 000000000..5e16f374b --- /dev/null +++ b/UIComposites/JSON.cs @@ -0,0 +1,18 @@ +using System.Text.Json; + +namespace UIComposites +{ + public static class JSON + { + public static async Task ReadAsync(string path, JsonSerializerOptions? opt = null) + { + using FileStream stream = File.OpenRead(path); + return await JsonSerializer.DeserializeAsync(stream, opt); + } + public static T? Read(string path, JsonSerializerOptions? opt = null) + { + return JsonSerializer.Deserialize(File.ReadAllText(path), opt); + } + public static void Write(string path, T obj, JsonSerializerOptions? opt = null) => File.WriteAllText(path, JsonSerializer.Serialize(obj, opt)); + } +} diff --git a/VolumeControl/Program.cs b/VolumeControl/Program.cs index 55e2bb75e..98b9da71e 100644 --- a/VolumeControl/Program.cs +++ b/VolumeControl/Program.cs @@ -1,11 +1,11 @@ using System.Diagnostics; -using System.Threading; -using System.Windows.Forms; +using UIComposites; namespace VolumeControl { internal static class Program { + //private static ColorSchemeList colors; // Entry point [STAThread] private static void Main() @@ -15,6 +15,14 @@ private static void Main() if (thisProc.Id != otherInst.Id) throw new Exception("An instance of Volume Control is already running!"); + //string themesDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\VolumeControl\themes"; + + //ColorScheme.DarkMode.SaveToFile(themesDir + @"\DarkMode.json"); + //ColorScheme.LightMode.SaveToFile(themesDir + @"\LightMode.json"); + + //colors = new(themesDir); + + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);