#nullable enable
using System.Collections;
using System.Collections.Specialized;
using System.Text.Json.Serialization;
namespace Terminal.Gui;
///
/// Holds the s that define the s that are used by views to render
/// themselves.
///
public sealed class Colors : INotifyCollectionChanged, IDictionary
{
static Colors ()
{
ColorSchemes = new (5, StringComparer.InvariantCultureIgnoreCase);
Reset ();
}
/// Gets a dictionary of defined objects.
///
///
/// The dictionary includes the following keys, by default:
///
///
/// Built-in Color Scheme Description
///
/// -
/// Base The base color scheme used for most Views.
///
/// -
/// TopLevel
/// The application Toplevel color scheme; used for the View.
///
/// -
/// Dialog
///
/// The dialog color scheme; used for , , and
/// other views dialog-like views.
///
///
/// -
/// Menu
///
/// The menu color scheme; used for , , and
/// .
///
///
/// -
/// Error
///
/// The color scheme for showing errors, such as in
/// .
///
///
///
///
/// Changing the values of an entry in this dictionary will affect all views that use the scheme.
///
/// can be used to override the default values for these schemes and add
/// additional schemes. See .
///
///
[SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
[JsonConverter (typeof (DictionaryJsonConverter))]
[UsedImplicitly]
public static Dictionary ColorSchemes { get; private set; }
///
public IEnumerator> GetEnumerator () { return ColorSchemes.GetEnumerator (); }
///
IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); }
///
public void Add (KeyValuePair item)
{
ColorSchemes.Add (item.Key, item.Value);
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Add, item));
}
///
public void Clear ()
{
ColorSchemes.Clear ();
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Reset));
}
///
public bool Contains (KeyValuePair item) { return ColorSchemes.Contains (item); }
///
public void CopyTo (KeyValuePair [] array, int arrayIndex) { ((ICollection)ColorSchemes).CopyTo (array, arrayIndex); }
///
public bool Remove (KeyValuePair item)
{
if (ColorSchemes.Remove (item.Key))
{
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Remove, item));
return true;
}
return false;
}
///
public int Count => ColorSchemes.Count;
///
public bool IsReadOnly => false;
///
public void Add (string key, ColorScheme? value) { Add (new (key, value)); }
///
public bool ContainsKey (string key) { return ColorSchemes.ContainsKey (key); }
///
public bool Remove (string key)
{
if (ColorSchemes.Remove (key))
{
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Remove, key));
return true;
}
return false;
}
///
public bool TryGetValue (string key, out ColorScheme? value) { return ColorSchemes.TryGetValue (key, out value); }
///
public ColorScheme? this [string key]
{
get => ColorSchemes [key];
set
{
if (ColorSchemes.TryAdd (key, value))
{
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Add, new KeyValuePair (key, value)));
}
else
{
ColorScheme? oldValue = ColorSchemes [key];
ColorSchemes [key] = value;
CollectionChanged?.Invoke (this, new (NotifyCollectionChangedAction.Replace, value, oldValue));
}
}
}
///
public ICollection Keys => ColorSchemes.Keys;
///
public ICollection Values => ColorSchemes.Values;
///
public event NotifyCollectionChangedEventHandler? CollectionChanged;
/// Resets the dictionary to the default values.
public static Dictionary Reset ()
{
ColorSchemes.Clear ();
ColorSchemes.Add ("TopLevel", new ());
ColorSchemes.Add ("Base", new ());
ColorSchemes.Add ("Dialog", new ());
ColorSchemes.Add ("Menu", new ());
ColorSchemes.Add ("Error", new ());
return ColorSchemes;
}
///
/// Open a with two or , based on the
/// is false or true, respectively, for
/// and colors.
///
/// The title to show in the dialog.
/// The current attribute used.
/// The new attribute.
/// if a new color was accepted, otherwise .
public static bool PromptForColors (string title, Attribute? currentAttribute, out Attribute newAttribute)
{
var accept = false;
var d = new Dialog
{
Title = title,
Width = Application.Force16Colors ? 37 : Dim.Auto (DimAutoStyle.Auto, Dim.Percent (80), Dim.Percent (90)),
Height = 20
};
var btnOk = new Button
{
X = Pos.Center () - 5,
Y = Application.Force16Colors ? 6 : 4,
Text = "Ok",
Width = Dim.Auto (),
IsDefault = true
};
btnOk.Accept += (s, e) =>
{
accept = true;
e.Handled = true;
Application.RequestStop ();
};
var btnCancel = new Button
{
X = Pos.Center () + 5,
Y = 4,
Text = "Cancel",
Width = Dim.Auto ()
};
btnCancel.Accept += (s, e) =>
{
e.Handled = true;
Application.RequestStop ();
};
d.Add (btnOk);
d.Add (btnCancel);
d.AddButton (btnOk);
d.AddButton (btnCancel);
View cpForeground;
if (Application.Force16Colors)
{
cpForeground = new ColorPicker16
{
SelectedColor = currentAttribute!.Value.Foreground.GetClosestNamedColor16 (),
Width = Dim.Fill (),
BorderStyle = LineStyle.Single,
Title = "Foreground"
};
}
else
{
cpForeground = new ColorPicker
{
SelectedColor = currentAttribute!.Value.Foreground,
Width = Dim.Fill (),
Style = new () { ShowColorName = true, ShowTextFields = true },
BorderStyle = LineStyle.Single,
Title = "Foreground"
};
((ColorPicker)cpForeground).ApplyStyleChanges ();
}
View cpBackground;
if (Application.Force16Colors)
{
cpBackground = new ColorPicker16
{
SelectedColor = currentAttribute!.Value.Background.GetClosestNamedColor16 (),
Y = Pos.Bottom (cpForeground) + 1,
Width = Dim.Fill (),
BorderStyle = LineStyle.Single,
Title = "Background"
};
}
else
{
cpBackground = new ColorPicker
{
SelectedColor = currentAttribute!.Value.Background,
Width = Dim.Fill (),
Y = Pos.Bottom (cpForeground) + 1,
Style = new () { ShowColorName = true, ShowTextFields = true },
BorderStyle = LineStyle.Single,
Title = "Background"
};
((ColorPicker)cpBackground).ApplyStyleChanges ();
}
d.Add (cpForeground, cpBackground);
Application.Run (d);
d.Dispose ();
Color newForeColor = Application.Force16Colors ? ((ColorPicker16)cpForeground).SelectedColor : ((ColorPicker)cpForeground).SelectedColor;
Color newBackColor = Application.Force16Colors ? ((ColorPicker16)cpBackground).SelectedColor : ((ColorPicker)cpBackground).SelectedColor;
newAttribute = new (newForeColor, newBackColor);
return accept;
}
}