namespace Terminal.Gui;
/// Event arguments for the events.
public class ColorEventArgs : EventArgs
{
/// Initializes a new instance of
public ColorEventArgs () { }
/// The new Thickness.
public Color Color { get; set; }
/// The previous Thickness.
public Color PreviousColor { get; set; }
}
/// The Color picker.
public class ColorPicker : View
{
/// Columns of color boxes
private readonly int _cols = 8;
/// Rows of color boxes
private readonly int _rows = 2;
private int _boxHeight = 2;
private int _boxWidth = 4;
private int _selectColorIndex = (int)Color.Black;
/// Initializes a new instance of .
public ColorPicker () { SetInitialProperties (); }
private void SetInitialProperties ()
{
HighlightStyle = Gui.HighlightStyle.PressedOutside | Gui.HighlightStyle.Pressed;
CanFocus = true;
AddCommands ();
AddKeyBindings ();
Width = Dim.Auto (minimumContentDim: _boxWidth * _cols);
Height = Dim.Auto (minimumContentDim: _boxHeight * _rows);
SetContentSize (new (_boxWidth * _cols, _boxHeight * _rows));
MouseClick += ColorPicker_MouseClick;
}
// TODO: Decouple Cursor from SelectedColor so that mouse press-and-hold can show the color under the cursor.
private void ColorPicker_MouseClick (object sender, MouseEventEventArgs me)
{
// if (CanFocus)
{
Cursor = new Point (me.MouseEvent.Position.X / _boxWidth, me.MouseEvent.Position.Y / _boxHeight);
SetFocus ();
me.Handled = true;
}
}
/// Height of a color box
public int BoxHeight
{
get => _boxHeight;
set
{
if (_boxHeight != value)
{
_boxHeight = value;
Width = Dim.Auto (minimumContentDim: _boxWidth * _cols);
Height = Dim.Auto (minimumContentDim: _boxHeight * _rows);
SetContentSize (new (_boxWidth * _cols, _boxHeight * _rows));
SetNeedsLayout ();
}
}
}
/// Width of a color box
public int BoxWidth
{
get => _boxWidth;
set
{
if (_boxWidth != value)
{
_boxWidth = value;
Width = Dim.Auto (minimumContentDim: _boxWidth * _cols);
Height = Dim.Auto (minimumContentDim: _boxHeight * _rows);
SetContentSize (new (_boxWidth * _cols, _boxHeight * _rows));
SetNeedsLayout ();
}
}
}
/// Cursor for the selected color.
public Point Cursor
{
get => new (_selectColorIndex % _cols, _selectColorIndex / _cols);
set
{
int colorIndex = value.Y * _cols + value.X;
SelectedColor = (ColorName)colorIndex;
}
}
/// Selected color.
public ColorName SelectedColor
{
get => (ColorName)_selectColorIndex;
set
{
if (value == (ColorName)_selectColorIndex)
{
return;
}
var prev = (ColorName)_selectColorIndex;
_selectColorIndex = (int)value;
ColorChanged?.Invoke (
this,
new ColorEventArgs { PreviousColor = new Color (prev), Color = new Color (value) }
);
SetNeedsDisplay ();
}
}
/// Fired when a color is picked.
public event EventHandler ColorChanged;
/// Moves the selected item index to the previous column.
///
public virtual bool MoveLeft ()
{
if (Cursor.X > 0)
{
SelectedColor--;
}
return true;
}
/// Moves the selected item index to the next column.
///
public virtual bool MoveRight ()
{
if (Cursor.X < _cols - 1)
{
SelectedColor++;
}
return true;
}
/// Moves the selected item index to the previous row.
///
public virtual bool MoveUp ()
{
if (Cursor.Y > 0)
{
SelectedColor -= _cols;
}
return true;
}
/// Moves the selected item index to the next row.
///
public virtual bool MoveDown ()
{
if (Cursor.Y < _rows - 1)
{
SelectedColor += _cols;
}
return true;
}
///
public override void OnDrawContent (Rectangle viewport)
{
base.OnDrawContent (viewport);
Driver.SetAttribute (HasFocus ? ColorScheme.Focus : GetNormalColor ());
var colorIndex = 0;
for (var y = 0; y < Math.Max (2, viewport.Height / BoxHeight); y++)
{
for (var x = 0; x < Math.Max (8, viewport.Width / BoxWidth); x++)
{
int foregroundColorIndex = y == 0 ? colorIndex + _cols : colorIndex - _cols;
Driver.SetAttribute (new Attribute ((ColorName)foregroundColorIndex, (ColorName)colorIndex));
bool selected = x == Cursor.X && y == Cursor.Y;
DrawColorBox (x, y, selected);
colorIndex++;
}
}
}
/// Add the commands.
private void AddCommands ()
{
AddCommand (Command.Left, () => MoveLeft ());
AddCommand (Command.Right, () => MoveRight ());
AddCommand (Command.LineUp, () => MoveUp ());
AddCommand (Command.LineDown, () => MoveDown ());
}
/// Add the KeyBindinds.
private void AddKeyBindings ()
{
KeyBindings.Add (Key.CursorLeft, Command.Left);
KeyBindings.Add (Key.CursorRight, Command.Right);
KeyBindings.Add (Key.CursorUp, Command.LineUp);
KeyBindings.Add (Key.CursorDown, Command.LineDown);
}
/// Draw a box for one color.
/// X location.
/// Y location
///
private void DrawColorBox (int x, int y, bool selected)
{
var index = 0;
for (var zoomedY = 0; zoomedY < BoxHeight; zoomedY++)
{
for (var zoomedX = 0; zoomedX < BoxWidth; zoomedX++)
{
Move (x * BoxWidth + zoomedX, y * BoxHeight + zoomedY);
Driver.AddRune ((Rune)' ');
index++;
}
}
if (selected)
{
DrawFocusRect (new (x * BoxWidth, y * BoxHeight, BoxWidth, BoxHeight));
}
}
private void DrawFocusRect (Rectangle rect)
{
var lc = new LineCanvas ();
if (rect.Width == 1)
{
lc.AddLine (rect.Location, rect.Height, Orientation.Vertical, LineStyle.Dotted);
}
else if (rect.Height == 1)
{
lc.AddLine (rect.Location, rect.Width, Orientation.Horizontal, LineStyle.Dotted);
}
else
{
lc.AddLine (rect.Location, rect.Width, Orientation.Horizontal, LineStyle.Dotted);
lc.AddLine (
rect.Location with { Y = rect.Location.Y + rect.Height - 1 },
rect.Width,
Orientation.Horizontal,
LineStyle.Dotted
);
lc.AddLine (rect.Location, rect.Height, Orientation.Vertical, LineStyle.Dotted);
lc.AddLine (
rect.Location with { X = rect.Location.X + rect.Width - 1 },
rect.Height,
Orientation.Vertical,
LineStyle.Dotted
);
}
foreach (KeyValuePair p in lc.GetMap ())
{
AddRune (p.Key.X, p.Key.Y, p.Value);
}
}
}