using System.ComponentModel; using System.Diagnostics; namespace PixiEditor.Extensions.CommonApi.UserPreferences.Settings; [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] public abstract class Setting : INotifyPropertyChanged { private readonly IPreferences preferences; private event PropertyChangedEventHandler PropertyChanged; /// /// The name of the preference /// public string Name { get; } /// /// The value of the preference /// public T? Value { get => GetValue(preferences, FallbackValue); set => SetValue(preferences, value); } /// /// The value used if the preference has not been set before /// public T? FallbackValue { get; } /// /// Called when the value of the preference has changed /// public event SettingChangedHandler ValueChanged; /// The name of the preference /// The value used if the preference has not been set before protected Setting(string name, T? fallbackValue = default) { SettingHelper.ThrowIfEmptySettingName(name); Name = name; FallbackValue = fallbackValue; preferences = IPreferences.Current; preferences.AddCallback(Name, SettingChangeCallback); } /// /// Gets the value of the preference or the if the preference has not been set before. Note: This will ignore the set in the setting constructor /// /// The value used if the preference has not been set before /// Either the value of the preference or public T GetValueOrDefault(T fallbackValue) => GetValue(preferences, fallbackValue); /// /// Gets the value of the preference as instead of the type defined by the setting. /// /// The value used if the preference has not been set before /// Either the value of the preference as or public TAny? As(TAny? fallbackValue = default) => GetValue(preferences, fallbackValue); protected abstract TAny? GetValue(IPreferences preferences, TAny fallbackValue); protected abstract void SetValue(IPreferences preferences, T? value); private void SettingChangeCallback(string name, T newValue) { ValueChanged?.Invoke(this, newValue); PropertyChanged?.Invoke(this, PropertyChangedConstants.ValueChangedPropertyArgs); } private string GetDebuggerDisplay() { string value; try { value = Value.ToString(); } catch (Exception e) { value = $"<{e.GetType()}: {e.Message}>"; } if (typeof(T) == typeof(string)) { value = $""" "{value}" """; } var type = typeof(T).ToString(); string preferenceType = this switch { LocalSetting => "local", SyncedSetting => "synced", _ => "" }; return $"{preferenceType} {Name}: {type} = {value}"; } event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add => PropertyChanged += value; remove => PropertyChanged -= value; } } // Generic types would create an instance for every type combination. file static class PropertyChangedConstants { public static readonly PropertyChangedEventArgs ValueChangedPropertyArgs = new("Value"); }