[ColorPicker]Custom color formats (#22141)

* [ColorPicker] Development: custom color formats, first steps

* ColorPicker development of custom format handling.

* Custom color format developmnet.
Added common helper class for format string
Fixed settings loading
Added numbering if default name exists   (My format (1))

* Custom color format implementation.
Extended the colorPicker settings with the format string
Updated the color to string conversion

* Custom color format in color picker, development.
Adding edit, delete buttons. Implement functionality
Re-arranging settings panel (newly created formats at the top)
Implementing details (valid parameters, more format elements, more types)

* Minor commit

* Development color picker custom formats. "Last" steps.
Replacing hard coded english strings with resources, polishing.

* Adding help to the format edit dialog.

* Undoing changes unwillingly commited in Host module

* Fixing bug unable to delete a custom format after renaming it - use the colorformat object as reference (and not the name)
Modifying the default custom formula
Removing unnecessary using directives

* Udating the default user defined color format

* Removing unnecessary using directive

* ColorPicker Implementing custom color formats: adding custom formats to the default format selection (dropdown box).

* Fix binding of name and example

* Custom color formats, implemented steps:
vorwarts compatibility loading settings.
Fixed UI as requested (removed one settings panel, added button to the first panel)

* Minor change in the UI: description modified

* ColorPicker Custom Color Formats develepoment.
Added conversion from old predefined formats to customizable formats.
Extended default settings (in case settings file is deleted/corrupted).
Minor fixes.

* Fixing color format parameters.
Implementing 3 different Saturation calculations, 2 Hue calculations and 2 Lightness calculations (depending color format)

* Color Picker: New/Edit Color format. Fixing bug when cancelling addition/edit

* ColorPicker. Updating help section, available parameters

* Fix spellchecker

* Remove the MinWidth so that scrollviewers can be drawn

* ColorPicker bugfix: Not allowing to delete the last color format.
This commit is contained in:
Laszlo Nemeth
2022-12-02 17:44:53 +01:00
committed by GitHub
parent 77dfaab17e
commit ec0fb6a4c7
35 changed files with 2324 additions and 1092 deletions

View File

@@ -4,22 +4,34 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using ManagedCommon;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class ColorFormatModel : INotifyPropertyChanged
{
private string _name;
private string _example;
private string _format;
private bool _isShown;
private bool _canMoveUp = true;
private bool _canMoveDown = true;
private bool _canBeDeleted = true;
private bool _isNew;
private bool _isValid = true;
public ColorFormatModel(string name, string example, bool isShown)
public ColorFormatModel(string name, string format, bool isShown)
{
Name = name;
Example = example;
Format = format;
IsShown = isShown;
IsNew = false;
}
public ColorFormatModel()
{
Format = "new Color (R = %Re, G = %Gr, B = %Bl)";
IsShown = true;
IsNew = true;
}
public string Name
@@ -32,21 +44,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
set
{
_name = value;
OnPropertyChanged();
OnPropertyChanged(nameof(Name));
}
}
public string Example
public string Format
{
get
{
return _example;
return _format;
}
set
{
_example = value;
OnPropertyChanged();
_format = value;
OnPropertyChanged(nameof(Format));
OnPropertyChanged(nameof(Example));
}
}
@@ -60,7 +73,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
set
{
_isShown = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsShown));
}
}
@@ -74,7 +87,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
set
{
_canMoveUp = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanMoveUp));
}
}
@@ -88,7 +101,64 @@ namespace Microsoft.PowerToys.Settings.UI.Library
set
{
_canMoveDown = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanMoveDown));
}
}
public bool CanBeDeleted
{
get
{
return _canBeDeleted;
}
set
{
if (value != _canBeDeleted)
{
_canBeDeleted = value;
OnPropertyChanged(nameof(CanBeDeleted));
}
}
}
public bool IsNew
{
get
{
return _isNew;
}
set
{
_isNew = value;
OnPropertyChanged(nameof(IsNew));
}
}
public bool IsValid
{
get
{
return _isValid;
}
set
{
_isValid = value;
OnPropertyChanged(nameof(IsValid));
}
}
public string Example
{
get
{
return ColorFormatHelper.GetStringRepresentation(null, _format);
}
set
{
}
}

View File

@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
namespace Microsoft.PowerToys.Settings.UI.Library
@@ -17,12 +18,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library
ChangeCursor = false;
ColorHistory = new List<string>();
ColorHistoryLimit = 20;
VisibleColorFormats = new Dictionary<string, bool>();
VisibleColorFormats.Add("HEX", true);
VisibleColorFormats.Add("RGB", true);
VisibleColorFormats.Add("HSL", true);
VisibleColorFormats = new Dictionary<string, KeyValuePair<bool, string>>();
VisibleColorFormats.Add("HEX", new KeyValuePair<bool, string>(true, ColorFormatHelper.GetDefaultFormat("HEX")));
VisibleColorFormats.Add("RGB", new KeyValuePair<bool, string>(true, ColorFormatHelper.GetDefaultFormat("RGB")));
VisibleColorFormats.Add("HSL", new KeyValuePair<bool, string>(true, ColorFormatHelper.GetDefaultFormat("HSL")));
VisibleColorFormats.Add("HSV", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HSV")));
VisibleColorFormats.Add("CMYK", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CMYK")));
VisibleColorFormats.Add("HSB", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HSB")));
VisibleColorFormats.Add("HSI", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HSI")));
VisibleColorFormats.Add("HWB", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HWB")));
VisibleColorFormats.Add("NCol", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("NCol")));
VisibleColorFormats.Add("CIELAB", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CIELAB")));
VisibleColorFormats.Add("CIEXYZ", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CIEXYZ")));
VisibleColorFormats.Add("VEC4", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("VEC4")));
VisibleColorFormats.Add("Decimal", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("Decimal")));
VisibleColorFormats.Add("HEX Int", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HEX Int")));
ShowColorName = false;
ActivationAction = ColorPickerActivationAction.OpenColorPickerAndThenEditor;
CopiedColorRepresentation = "HEX";
}
public HotkeySettings ActivationShortcut { get; set; }
@@ -32,7 +45,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public bool ChangeCursor { get; set; }
[JsonPropertyName("copiedcolorrepresentation")]
public ColorRepresentationType CopiedColorRepresentation { get; set; }
public string CopiedColorRepresentation { get; set; }
[JsonPropertyName("activationaction")]
public ColorPickerActivationAction ActivationAction { get; set; }
@@ -44,7 +57,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public int ColorHistoryLimit { get; set; }
[JsonPropertyName("visiblecolorformats")]
public Dictionary<string, bool> VisibleColorFormats { get; set; }
public Dictionary<string, KeyValuePair<bool, string>> VisibleColorFormats { get; set; }
[JsonPropertyName("showcolorname")]
[JsonConverter(typeof(BoolPropertyJsonConverter))]

View File

@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class ColorPickerPropertiesVersion1
{
public ColorPickerPropertiesVersion1()
{
ActivationShortcut = new HotkeySettings(true, false, false, true, 0x43);
ChangeCursor = false;
ColorHistory = new List<string>();
ColorHistoryLimit = 20;
VisibleColorFormats = new Dictionary<string, bool>();
VisibleColorFormats.Add("HEX", true);
VisibleColorFormats.Add("RGB", true);
VisibleColorFormats.Add("HSL", true);
ShowColorName = false;
ActivationAction = ColorPickerActivationAction.OpenColorPickerAndThenEditor;
}
public HotkeySettings ActivationShortcut { get; set; }
[JsonPropertyName("changecursor")]
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool ChangeCursor { get; set; }
[JsonPropertyName("copiedcolorrepresentation")]
public ColorRepresentationType CopiedColorRepresentation { get; set; }
[JsonPropertyName("activationaction")]
public ColorPickerActivationAction ActivationAction { get; set; }
[JsonPropertyName("colorhistory")]
public List<string> ColorHistory { get; set; }
[JsonPropertyName("colorhistorylimit")]
public int ColorHistoryLimit { get; set; }
[JsonPropertyName("visiblecolorformats")]
public Dictionary<string, bool> VisibleColorFormats { get; set; }
[JsonPropertyName("showcolorname")]
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool ShowColorName { get; set; }
public override string ToString()
=> JsonSerializer.Serialize(this);
}
}

View File

@@ -3,8 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library
@@ -19,7 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public ColorPickerSettings()
{
Properties = new ColorPickerProperties();
Version = "1";
Version = "2";
Name = ModuleName;
}
@@ -45,5 +48,26 @@ namespace Microsoft.PowerToys.Settings.UI.Library
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
=> false;
public static object UpgradeSettings(object oldSettingsObject)
{
ColorPickerSettingsVersion1 oldSettings = (ColorPickerSettingsVersion1)oldSettingsObject;
ColorPickerSettings newSettings = new ColorPickerSettings();
newSettings.Properties.ActivationShortcut = oldSettings.Properties.ActivationShortcut;
newSettings.Properties.ChangeCursor = oldSettings.Properties.ChangeCursor;
newSettings.Properties.ActivationAction = oldSettings.Properties.ActivationAction;
newSettings.Properties.ColorHistory = new List<string>(oldSettings.Properties.ColorHistory);
newSettings.Properties.ColorHistoryLimit = oldSettings.Properties.ColorHistoryLimit;
newSettings.Properties.ShowColorName = oldSettings.Properties.ShowColorName;
newSettings.Properties.ActivationShortcut = oldSettings.Properties.ActivationShortcut;
newSettings.Properties.VisibleColorFormats = new Dictionary<string, KeyValuePair<bool, string>>();
foreach (KeyValuePair<string, bool> oldValue in oldSettings.Properties.VisibleColorFormats)
{
newSettings.Properties.VisibleColorFormats.Add(oldValue.Key, new KeyValuePair<bool, string>(oldValue.Value, ColorFormatHelper.GetDefaultFormat(oldValue.Key)));
}
newSettings.Properties.CopiedColorRepresentation = newSettings.Properties.VisibleColorFormats.ElementAt((int)oldSettings.Properties.CopiedColorRepresentation).Key;
return newSettings;
}
}
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class ColorPickerSettingsVersion1 : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "ColorPicker";
[JsonPropertyName("properties")]
public ColorPickerPropertiesVersion1 Properties { get; set; }
public ColorPickerSettingsVersion1()
{
Properties = new ColorPickerPropertiesVersion1();
Version = "1";
Name = ModuleName;
}
public virtual void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
if (settingsUtils == null)
{
throw new ArgumentNullException(nameof(settingsUtils));
}
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}
public string GetModuleName()
=> Name;
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
=> false;
}
}

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library
@@ -21,5 +22,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
void DeleteSettings(string powertoy = "");
string GetSettingsFilePath(string powertoy = "", string fileName = "settings.json");
T GetSettingsOrDefault<T, T2>(string powertoy = "", string fileName = "settings.json", Func<object, object> settingsUpgrader = null)
where T : ISettingsConfig, new()
where T2 : ISettingsConfig, new();
}
}

View File

@@ -96,6 +96,50 @@ namespace Microsoft.PowerToys.Settings.UI.Library
return newSettingsItem;
}
/// <summary>
/// Get a Deserialized object of the json settings string.
/// This function creates a file in the powertoy folder if it does not exist and returns an object with default properties.
/// </summary>
/// <returns>Deserialized json settings object.</returns>
public T GetSettingsOrDefault<T, T2>(string powertoy = DefaultModuleName, string fileName = DefaultFileName, Func<object, object> settingsUpgrader = null)
where T : ISettingsConfig, new()
where T2 : ISettingsConfig, new()
{
try
{
return GetSettings<T>(powertoy, fileName);
}
// Catch json deserialization exceptions when the file is corrupt and has an invalid json.
// If there are any deserialization issues like in https://github.com/microsoft/PowerToys/issues/7500, log the error and create a new settings.json file.
// This is different from the case where we have trailing zeros following a valid json file, which we have handled by trimming the trailing zeros.
catch (JsonException ex)
{
Logger.LogError($"Exception encountered while loading {powertoy} settings.", ex);
// try to deserialize to the old format, which is presented in T2
try
{
T2 oldSettings = GetSettings<T2>(powertoy, fileName);
T newSettings = (T)settingsUpgrader(oldSettings);
return newSettings;
}
catch (Exception)
{
// do nothing, the problem wasn't that the settings was stored in the previous format, continue with the default settings
}
}
catch (FileNotFoundException)
{
Logger.LogInfo($"Settings file {fileName} for {powertoy} was not found.");
}
// If the settings file does not exist or if the file is corrupt, to create a new object with default parameters and save it to a newly created settings file.
T newSettingsItem = new T();
SaveSettings(newSettingsItem.ToJsonString(), powertoy, fileName);
return newSettingsItem;
}
// Given the powerToy folder name and filename to be accessed, this function deserializes and returns the file.
private T GetFile<T>(string powertoyFolderName = DefaultModuleName, string fileName = DefaultFileName)
{