Fixes #2800 - Color picker (supporting hsl, hsv and rgb) (#3604)

* Readonly HSL view

* Make it possible to move between bars by moving to subview

* Basically working and with mouse support

* Fix HSL to work properly with double values instead of color matching

* Fix Value on ColorPicker to match HSL values

* Fix color spectrum

* Add Swatch and better sync with text box

* Work on jitter

* ColorPicker HSL working

* More keybindings

* Add ColorModel

* Support both HSL and HSV

* Add RGB

* Better mouse handling

* WIP: AttributeView and integrate into LineDrawing
(does not currently work properly)

* Fix color picking

* Add concept of an ITool

* Add ColorPickerStyle

* Fix selected cell rendering

* Add first test for ColorPicker2

* Add more RGB tests

* Improve ColorPicker2 setup process

* Tests and fixes for keyboard changing value R

* Fix margin on bars when no textfields

* Add mouse test

* Add tests for with text field

* Add more tests and fix bug sync component text field change with hex text field

(WIP - failing tests)

* Fix tests and fix clicking in a bar label area possibly not selecting

* Move AttributeView to LineDrawing and adjust to have a 'transparent pattern' too

* Render triangle in dark gray if background is black

* Add ColorChanged event

* Resharper Cleanup

* Xml comments and public/private adjustments

* Explore replacing diagram test with fragile Subview diving

* Migrate ColorPicker_DefaultBoot to sub asserts

* Port other tests

* Replace ColorPicker with new view

* Fix ColorPicker size to match scenarios size assumptions

* Split to separate files and ignore invalid test for ColorPicker

* Ignore also in mouse version of AllViews_Enter_Leave_Events

* Remove bool _updating from ColorPicker

Now instead we are more selective about what we update when and do so deterministically

* Typo fix

* Fix ReSharper bad renames in comments for "Value"

* Refactor to single implementation of 'prompt for color' logic

- Now called PromptForColor
- Shared by LineDrawing and ProgressBarStyles scenarios

* Sum runes instead of Length

* Hide ColorBar and SetValueWithoutRaisingEvent from public API

* Move ColorEventArgs to Drawing folder

* Move ColorModel to Drawing folder

* First try at Dim.Auto for ColorPicker

* Remove explicit width/height setting in most scenarios

* Remove explicit heights

* Fixed build/test issues.
Illustrated test best practice.

* WIP: Start working on test changes and add new options to ColorPickers scenario (Color Model and show textfields).

* Fix for R indicator arrow sometimes 'falling off' the drawn area.

* Add nullable enable

* Test fixes and refactor for avoiding Begin

* Make ColorEventArgs inherit from EventArgs<Color>

* Fix Dispose not being called on bars when switching color models

* Remove 'oldColor' from test now it is not supported

* Add initial stab at ColorPickerStyle.ShowName

* Use AppendAutocomplete for color names

* Implemented resoruce based colorname resolver

* Update GetTextField to support getting the color names field
Change style setting to ShowColorName

* Color name updates when navigating away from the named color

* Restore old color picker as ColorPicker16

* Add test that shows 'Save as' is currently considered a named color ><

* Fix GetW3CColorNames

* Removed dupe colors

* Revert to old color pickers

* Nullability question marks for everyone!

---------

Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
Thomas Nind
2024-08-23 00:53:04 +01:00
committed by GitHub
parent e95f821f2b
commit 38f84f7424
30 changed files with 4507 additions and 615 deletions

View File

@@ -8,7 +8,7 @@ namespace UICatalog.Scenarios;
/// </summary>
public class AdornmentEditor : View
{
private readonly ColorPicker _backgroundColorPicker = new ()
private readonly ColorPicker16 _backgroundColorPicker = new ()
{
Title = "_BG",
BoxWidth = 1,
@@ -18,7 +18,7 @@ public class AdornmentEditor : View
Enabled = false
};
private readonly ColorPicker _foregroundColorPicker = new ()
private readonly ColorPicker16 _foregroundColorPicker = new ()
{
Title = "_FG",
BoxWidth = 1,

View File

@@ -38,7 +38,7 @@ public class Adornments : Scenario
app.Add (window);
var tf1 = new TextField { Width = 10, Text = "TextField" };
var color = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
var color = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
color.BorderStyle = LineStyle.RoundedDotted;
color.ColorChanged += (s, e) =>
@@ -47,7 +47,7 @@ public class Adornments : Scenario
{
Normal = new (
color.SuperView.ColorScheme.Normal.Foreground,
e.Color
e.CurrentValue
)
};
};

View File

@@ -23,6 +23,12 @@ public class ColorPickers : Scenario
/// <summary>Foreground ColorPicker.</summary>
private ColorPicker foregroundColorPicker;
/// <summary>Background ColorPicker.</summary>
private ColorPicker16 backgroundColorPicker16;
/// <summary>Foreground ColorPicker.</summary>
private ColorPicker16 foregroundColorPicker16;
/// <summary>Setup the scenario.</summary>
public override void Main ()
{
@@ -33,8 +39,16 @@ public class ColorPickers : Scenario
Title = GetQuitKeyAndName (),
};
///////////////////////////////////////
// True Color Pickers
///////////////////////////////////////
// Foreground ColorPicker.
foregroundColorPicker = new ColorPicker { Title = "Foreground Color", BorderStyle = LineStyle.Single };
foregroundColorPicker = new ColorPicker {
Title = "Foreground Color",
BorderStyle = LineStyle.Single,
Width = Dim.Percent (50)
};
foregroundColorPicker.ColorChanged += ForegroundColor_ColorChanged;
app.Add (foregroundColorPicker);
@@ -49,9 +63,8 @@ public class ColorPickers : Scenario
{
Title = "Background Color",
X = Pos.AnchorEnd (),
BoxHeight = 1,
BoxWidth = 4,
BorderStyle = LineStyle.Single,
Width = Dim.Percent (50),
BorderStyle = LineStyle.Single
};
backgroundColorPicker.ColorChanged += BackgroundColor_ColorChanged;
@@ -64,6 +77,37 @@ public class ColorPickers : Scenario
app.Add (_backgroundColorLabel);
///////////////////////////////////////
// 16 Color Pickers
///////////////////////////////////////
// Foreground ColorPicker 16.
foregroundColorPicker16 = new ColorPicker16
{
Title = "Foreground Color",
BorderStyle = LineStyle.Single,
Width = Dim.Percent (50),
Visible = false // We default to HSV so hide old one
};
foregroundColorPicker16.ColorChanged += ForegroundColor_ColorChanged;
app.Add (foregroundColorPicker16);
// Background ColorPicker 16.
backgroundColorPicker16 = new ColorPicker16
{
Title = "Background Color",
X = Pos.AnchorEnd (),
Width = Dim.Percent (50),
BorderStyle = LineStyle.Single,
Visible = false // We default to HSV so hide old one
};
backgroundColorPicker16.ColorChanged += BackgroundColor_ColorChanged;
app.Add (backgroundColorPicker16);
// Demo Label.
_demoView = new View
{
@@ -79,6 +123,98 @@ public class ColorPickers : Scenario
};
app.Add (_demoView);
// Radio for switching color models
var rgColorModel = new RadioGroup ()
{
Y = Pos.Bottom (_demoView),
Width = Dim.Auto (),
Height = Dim.Auto (),
RadioLabels = new []
{
"RGB",
"HSV",
"HSL",
"16 Colors"
},
SelectedItem = (int)foregroundColorPicker.Style.ColorModel,
};
rgColorModel.SelectedItemChanged += (_, e) =>
{
// 16 colors
if (e.SelectedItem == 3)
{
foregroundColorPicker16.Visible = true;
foregroundColorPicker.Visible = false;
backgroundColorPicker16.Visible = true;
backgroundColorPicker.Visible = false;
// Switching to 16 colors
ForegroundColor_ColorChanged (null,null);
BackgroundColor_ColorChanged (null, null);
}
else
{
foregroundColorPicker16.Visible = false;
foregroundColorPicker.Visible = true;
foregroundColorPicker.Style.ColorModel = (ColorModel)e.SelectedItem;
foregroundColorPicker.ApplyStyleChanges ();
backgroundColorPicker16.Visible = false;
backgroundColorPicker.Visible = true;
backgroundColorPicker.Style.ColorModel = (ColorModel)e.SelectedItem;
backgroundColorPicker.ApplyStyleChanges ();
// Switching to true colors
foregroundColorPicker.SelectedColor = foregroundColorPicker16.SelectedColor;
backgroundColorPicker.SelectedColor = backgroundColorPicker16.SelectedColor;
}
};
app.Add (rgColorModel);
// Checkbox for switching show text fields on and off
var cbShowTextFields = new CheckBox ()
{
Text = "Show Text Fields",
Y = Pos.Bottom (rgColorModel)+1,
Width = Dim.Auto (),
Height = Dim.Auto (),
CheckedState = foregroundColorPicker.Style.ShowTextFields ? CheckState.Checked: CheckState.UnChecked,
};
cbShowTextFields.CheckedStateChanging += (_, e) =>
{
foregroundColorPicker.Style.ShowTextFields = e.NewValue == CheckState.Checked;
foregroundColorPicker.ApplyStyleChanges ();
backgroundColorPicker.Style.ShowTextFields = e.NewValue == CheckState.Checked;
backgroundColorPicker.ApplyStyleChanges ();
};
app.Add (cbShowTextFields);
// Checkbox for switching show text fields on and off
var cbShowName = new CheckBox ()
{
Text = "Show Color Name",
Y = Pos.Bottom (cbShowTextFields) + 1,
Width = Dim.Auto (),
Height = Dim.Auto (),
CheckedState = foregroundColorPicker.Style.ShowColorName ? CheckState.Checked : CheckState.UnChecked,
};
cbShowName.CheckedStateChanging += (_, e) =>
{
foregroundColorPicker.Style.ShowColorName = e.NewValue == CheckState.Checked;
foregroundColorPicker.ApplyStyleChanges ();
backgroundColorPicker.Style.ShowColorName = e.NewValue == CheckState.Checked;
backgroundColorPicker.ApplyStyleChanges ();
};
app.Add (cbShowName);
// Set default colors.
foregroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Foreground.GetClosestNamedColor ();
backgroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Background.GetClosestNamedColor ();
@@ -92,25 +228,32 @@ public class ColorPickers : Scenario
/// <summary>Fired when background color is changed.</summary>
private void BackgroundColor_ColorChanged (object sender, EventArgs e)
{
UpdateColorLabel (_backgroundColorLabel, backgroundColorPicker);
UpdateColorLabel (_backgroundColorLabel,
backgroundColorPicker.Visible ?
backgroundColorPicker.SelectedColor :
backgroundColorPicker16.SelectedColor
);
UpdateDemoLabel ();
}
/// <summary>Fired when foreground color is changed.</summary>
private void ForegroundColor_ColorChanged (object sender, EventArgs e)
{
UpdateColorLabel (_foregroundColorLabel, foregroundColorPicker);
UpdateColorLabel (_foregroundColorLabel,
foregroundColorPicker.Visible ?
foregroundColorPicker.SelectedColor :
foregroundColorPicker16.SelectedColor
);
UpdateDemoLabel ();
}
/// <summary>Update a color label from his ColorPicker.</summary>
private void UpdateColorLabel (Label label, ColorPicker colorPicker)
private void UpdateColorLabel (Label label, Color color)
{
label.Clear ();
var color = new Color (colorPicker.SelectedColor);
label.Text =
$"{colorPicker.SelectedColor} ({(int)colorPicker.SelectedColor}) #{color.R:X2}{color.G:X2}{color.B:X2}";
$"{color} ({(int)color}) #{color.R:X2}{color.G:X2}{color.B:X2}";
}
/// <summary>Update Demo Label.</summary>
@@ -119,8 +262,12 @@ public class ColorPickers : Scenario
_demoView.ColorScheme = new ColorScheme
{
Normal = new Attribute (
foregroundColorPicker.SelectedColor,
backgroundColorPicker.SelectedColor
foregroundColorPicker.Visible ?
foregroundColorPicker.SelectedColor :
foregroundColorPicker16.SelectedColor,
backgroundColorPicker.Visible ?
backgroundColorPicker.SelectedColor :
backgroundColorPicker16.SelectedColor
)
};
}

View File

@@ -326,7 +326,7 @@ public class ContentScrolling : Scenario
// Add demo views to show that things work correctly
var textField = new TextField { X = 20, Y = 7, Width = 15, Text = "Test TextField" };
var colorPicker = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (), Y = 10 };
var colorPicker = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (), Y = 10 };
colorPicker.BorderStyle = LineStyle.RoundedDotted;
colorPicker.ColorChanged += (s, e) =>
@@ -335,7 +335,7 @@ public class ContentScrolling : Scenario
{
Normal = new (
colorPicker.SuperView.ColorScheme.Normal.Foreground,
e.Color
e.CurrentValue
)
};
};

View File

@@ -1,10 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Terminal.Gui;
namespace UICatalog.Scenarios;
public interface ITool
{
void OnMouseEvent (DrawingArea area, MouseEvent mouseEvent);
}
internal class DrawLineTool : ITool
{
private StraightLine _currentLine;
public LineStyle LineStyle { get; set; } = LineStyle.Single;
/// <inheritdoc/>
public void OnMouseEvent (DrawingArea area, MouseEvent mouseEvent)
{
if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
{
if (_currentLine == null)
{
// Mouse pressed down
_currentLine = new (
mouseEvent.Position,
0,
Orientation.Vertical,
LineStyle,
area.CurrentAttribute
);
area.CurrentLayer.AddLine (_currentLine);
}
else
{
// Mouse dragged
Point start = _currentLine.Start;
Point end = mouseEvent.Position;
var orientation = Orientation.Vertical;
int length = end.Y - start.Y;
// if line is wider than it is tall switch to horizontal
if (Math.Abs (start.X - end.X) > Math.Abs (start.Y - end.Y))
{
orientation = Orientation.Horizontal;
length = end.X - start.X;
}
if (length > 0)
{
length++;
}
else
{
length--;
}
_currentLine.Length = length;
_currentLine.Orientation = orientation;
area.CurrentLayer.ClearCache ();
area.SetNeedsDisplay ();
}
}
else
{
// Mouse released
if (_currentLine != null)
{
if (_currentLine.Length == 0)
{
_currentLine.Length = 1;
}
if (_currentLine.Style == LineStyle.None)
{
// Treat none as eraser
int idx = area.Layers.IndexOf (area.CurrentLayer);
area.Layers.Remove (area.CurrentLayer);
area.CurrentLayer = new (
area.CurrentLayer.Lines.Exclude (
_currentLine.Start,
_currentLine.Length,
_currentLine.Orientation
)
);
area.Layers.Insert (idx, area.CurrentLayer);
}
_currentLine = null;
area.ClearUndo ();
area.SetNeedsDisplay ();
}
}
}
}
[ScenarioMetadata ("Line Drawing", "Demonstrates LineCanvas.")]
[ScenarioCategory ("Controls")]
[ScenarioCategory ("Drawing")]
@@ -18,12 +112,14 @@ public class LineDrawing : Scenario
var tools = new ToolsView { Title = "Tools", X = Pos.Right (canvas) - 20, Y = 2 };
tools.ColorChanged += c => canvas.SetColor (c);
tools.SetStyle += b => canvas.LineStyle = b;
tools.ColorChanged += (s, e) => canvas.SetAttribute (e);
tools.SetStyle += b => canvas.CurrentTool = new DrawLineTool { LineStyle = b };
tools.AddLayer += () => canvas.AddLayer ();
win.Add (canvas);
win.Add (tools);
tools.CurrentColor = canvas.GetNormalColor ();
canvas.CurrentAttribute = tools.CurrentColor;
win.KeyDown += (s, e) => { e.Handled = canvas.OnKeyDown (e); };
@@ -32,206 +128,329 @@ public class LineDrawing : Scenario
Application.Shutdown ();
}
private class DrawingArea : View
public static bool PromptForColor (string title, Color current, out Color newColor)
{
private readonly List<LineCanvas> _layers = new ();
private readonly Stack<StraightLine> _undoHistory = new ();
private Color _currentColor = new (Color.White);
private LineCanvas _currentLayer;
private StraightLine _currentLine;
public DrawingArea () { AddLayer (); }
public LineStyle LineStyle { get; set; }
var accept = false;
public override void OnDrawContentComplete (Rectangle viewport)
var d = new Dialog
{
base.OnDrawContentComplete (viewport);
Title = title,
Height = 7
};
foreach (LineCanvas canvas in _layers)
var btnOk = new Button
{
X = Pos.Center () - 5,
Y = 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);
/* Does not work
d.AddButton (btnOk);
d.AddButton (btnCancel);
*/
var cp = new ColorPicker
{
SelectedColor = current,
Width = Dim.Fill ()
};
d.Add (cp);
Application.Run (d);
d.Dispose ();
newColor = cp.SelectedColor;
return accept;
}
}
public class ToolsView : Window
{
private Button _addLayerBtn;
private readonly AttributeView _colors;
private RadioGroup _stylePicker;
public Attribute CurrentColor
{
get => _colors.Value;
set => _colors.Value = value;
}
public ToolsView ()
{
BorderStyle = LineStyle.Dotted;
Border.Thickness = new (1, 2, 1, 1);
Initialized += ToolsView_Initialized;
_colors = new ();
}
public event Action AddLayer;
public override void BeginInit ()
{
base.BeginInit ();
_colors.ValueChanged += (s, e) => ColorChanged?.Invoke (this, e);
_stylePicker = new()
{
X = 0, Y = Pos.Bottom (_colors), RadioLabels = Enum.GetNames (typeof (LineStyle)).ToArray ()
};
_stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem); };
_stylePicker.SelectedItem = 1;
_addLayerBtn = new() { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
_addLayerBtn.Accept += (s, a) => AddLayer?.Invoke ();
Add (_colors, _stylePicker, _addLayerBtn);
}
public event EventHandler<Attribute> ColorChanged;
public event Action<LineStyle> SetStyle;
private void ToolsView_Initialized (object sender, EventArgs e)
{
LayoutSubviews ();
Width = Math.Max (_colors.Frame.Width, _stylePicker.Frame.Width) + GetAdornmentsThickness ().Horizontal;
Height = _colors.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetAdornmentsThickness ().Vertical;
SuperView.LayoutSubviews ();
}
}
public class DrawingArea : View
{
public readonly List<LineCanvas> Layers = new ();
private readonly Stack<StraightLine> _undoHistory = new ();
public Attribute CurrentAttribute { get; set; }
public LineCanvas CurrentLayer { get; set; }
public ITool CurrentTool { get; set; } = new DrawLineTool ();
public DrawingArea () { AddLayer (); }
public override void OnDrawContentComplete (Rectangle viewport)
{
base.OnDrawContentComplete (viewport);
foreach (LineCanvas canvas in Layers)
{
foreach (KeyValuePair<Point, Cell?> c in canvas.GetCellMap ())
{
foreach (KeyValuePair<Point, Cell?> c in canvas.GetCellMap ())
if (c.Value is { })
{
if (c.Value is { })
{
Driver.SetAttribute (c.Value.Value.Attribute ?? ColorScheme.Normal);
Driver.SetAttribute (c.Value.Value.Attribute ?? ColorScheme.Normal);
// TODO: #2616 - Support combining sequences that don't normalize
AddRune (c.Key.X, c.Key.Y, c.Value.Value.Rune);
}
// TODO: #2616 - Support combining sequences that don't normalize
AddRune (c.Key.X, c.Key.Y, c.Value.Value.Rune);
}
}
}
}
//// BUGBUG: Why is this not handled by a key binding???
public override bool OnKeyDown (Key e)
//// BUGBUG: Why is this not handled by a key binding???
public override bool OnKeyDown (Key e)
{
// BUGBUG: These should be implemented with key bindings
if (e.KeyCode == (KeyCode.Z | KeyCode.CtrlMask))
{
// BUGBUG: These should be implemented with key bindings
if (e.KeyCode == (KeyCode.Z | KeyCode.CtrlMask))
StraightLine pop = CurrentLayer.RemoveLastLine ();
if (pop != null)
{
StraightLine pop = _currentLayer.RemoveLastLine ();
_undoHistory.Push (pop);
SetNeedsDisplay ();
if (pop != null)
{
_undoHistory.Push (pop);
SetNeedsDisplay ();
return true;
}
return true;
}
if (e.KeyCode == (KeyCode.Y | KeyCode.CtrlMask))
{
if (_undoHistory.Any ())
{
StraightLine pop = _undoHistory.Pop ();
_currentLayer.AddLine (pop);
SetNeedsDisplay ();
return true;
}
}
return false;
}
protected override bool OnMouseEvent (MouseEvent mouseEvent)
if (e.KeyCode == (KeyCode.Y | KeyCode.CtrlMask))
{
if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
if (_undoHistory.Any ())
{
if (_currentLine == null)
{
// Mouse pressed down
_currentLine = new StraightLine (
mouseEvent.Position,
0,
Orientation.Vertical,
LineStyle,
new Attribute (_currentColor, GetNormalColor ().Background)
);
StraightLine pop = _undoHistory.Pop ();
CurrentLayer.AddLine (pop);
SetNeedsDisplay ();
_currentLayer.AddLine (_currentLine);
}
else
{
// Mouse dragged
Point start = _currentLine.Start;
var end = mouseEvent.Position;
var orientation = Orientation.Vertical;
int length = end.Y - start.Y;
return true;
}
}
// if line is wider than it is tall switch to horizontal
if (Math.Abs (start.X - end.X) > Math.Abs (start.Y - end.Y))
{
orientation = Orientation.Horizontal;
length = end.X - start.X;
}
return false;
}
if (length > 0)
{
length++;
}
else
{
length--;
}
protected override bool OnMouseEvent (MouseEvent mouseEvent)
{
CurrentTool.OnMouseEvent (this, mouseEvent);
_currentLine.Length = length;
_currentLine.Orientation = orientation;
_currentLayer.ClearCache ();
SetNeedsDisplay ();
}
return base.OnMouseEvent (mouseEvent);
}
internal void AddLayer ()
{
CurrentLayer = new ();
Layers.Add (CurrentLayer);
}
internal void SetAttribute (Attribute a) { CurrentAttribute = a; }
public void ClearUndo () { _undoHistory.Clear (); }
}
public class AttributeView : View
{
public event EventHandler<Attribute> ValueChanged;
private Attribute _value;
public Attribute Value
{
get => _value;
set
{
_value = value;
ValueChanged?.Invoke (this, value);
}
}
private static readonly HashSet<(int, int)> ForegroundPoints = new()
{
(0, 0), (1, 0), (2, 0),
(0, 1), (1, 1), (2, 1)
};
private static readonly HashSet<(int, int)> BackgroundPoints = new()
{
(3, 1),
(1, 2), (2, 2), (3, 2)
};
public AttributeView ()
{
Width = 4;
Height = 3;
}
/// <inheritdoc/>
public override void OnDrawContent (Rectangle viewport)
{
base.OnDrawContent (viewport);
Color fg = Value.Foreground;
Color bg = Value.Background;
bool isTransparentFg = fg == GetNormalColor ().Background;
bool isTransparentBg = bg == GetNormalColor ().Background;
Driver.SetAttribute (new (fg, isTransparentFg ? Color.Gray : fg));
// Square of foreground color
foreach ((int, int) point in ForegroundPoints)
{
// Make pattern like this when it is same color as background of control
/*▓▒
▒▓*/
Rune rune;
if (isTransparentFg)
{
rune = (Rune)(point.Item1 % 2 == point.Item2 % 2 ? '▓' : '▒');
}
else
{
// Mouse released
if (_currentLine != null)
{
if (_currentLine.Length == 0)
{
_currentLine.Length = 1;
}
if (_currentLine.Style == LineStyle.None)
{
// Treat none as eraser
int idx = _layers.IndexOf (_currentLayer);
_layers.Remove (_currentLayer);
_currentLayer = new LineCanvas (
_currentLayer.Lines.Exclude (
_currentLine.Start,
_currentLine.Length,
_currentLine.Orientation
)
);
_layers.Insert (idx, _currentLayer);
}
_currentLine = null;
_undoHistory.Clear ();
SetNeedsDisplay ();
}
rune = (Rune)'█';
}
return base.OnMouseEvent (mouseEvent);
AddRune (point.Item1, point.Item2, rune);
}
internal void AddLayer ()
Driver.SetAttribute (new (bg, isTransparentBg ? Color.Gray : bg));
// Square of background color
foreach ((int, int) point in BackgroundPoints)
{
_currentLayer = new LineCanvas ();
_layers.Add (_currentLayer);
}
// Make pattern like this when it is same color as background of control
/*▓▒
▒▓*/
Rune rune;
internal void SetColor (Color c) { _currentColor = c; }
if (isTransparentBg)
{
rune = (Rune)(point.Item1 % 2 == point.Item2 % 2 ? '▓' : '▒');
}
else
{
rune = (Rune)'█';
}
AddRune (point.Item1, point.Item2, rune);
}
}
private class ToolsView : Window
/// <inheritdoc/>
protected override bool OnMouseEvent (MouseEvent mouseEvent)
{
private Button _addLayerBtn;
private ColorPicker _colorPicker;
private RadioGroup _stylePicker;
public ToolsView ()
if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked))
{
BorderStyle = LineStyle.Dotted;
Border.Thickness = new Thickness (1, 2, 1, 1);
Initialized += ToolsView_Initialized;
}
public event Action AddLayer;
public override void BeginInit ()
{
base.BeginInit ();
_colorPicker = new ColorPicker { X = 0, Y = 0, BoxHeight = 1, BoxWidth = 2 };
_colorPicker.ColorChanged += (s, a) => ColorChanged?.Invoke (a.Color);
_stylePicker = new RadioGroup
if (IsForegroundPoint (mouseEvent.Position.X, mouseEvent.Position.Y))
{
X = 0, Y = Pos.Bottom (_colorPicker), RadioLabels = Enum.GetNames (typeof (LineStyle)).ToArray ()
};
_stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem); };
_stylePicker.SelectedItem = 1;
_addLayerBtn = new Button { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
_addLayerBtn.Accept += (s, a) => AddLayer?.Invoke ();
Add (_colorPicker, _stylePicker, _addLayerBtn);
ClickedInForeground ();
}
else if (IsBackgroundPoint (mouseEvent.Position.X, mouseEvent.Position.Y))
{
ClickedInBackground ();
}
}
public event Action<Color> ColorChanged;
public event Action<LineStyle> SetStyle;
return base.OnMouseEvent (mouseEvent);
}
private void ToolsView_Initialized (object sender, EventArgs e)
private bool IsForegroundPoint (int x, int y) { return ForegroundPoints.Contains ((x, y)); }
private bool IsBackgroundPoint (int x, int y) { return BackgroundPoints.Contains ((x, y)); }
private void ClickedInBackground ()
{
if (LineDrawing.PromptForColor ("Background", Value.Background, out Color newColor))
{
LayoutSubviews ();
Value = new (Value.Foreground, newColor);
SetNeedsDisplay ();
}
}
Width = Math.Max (_colorPicker.Frame.Width, _stylePicker.Frame.Width) + GetAdornmentsThickness ().Horizontal;
Height = _colorPicker.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetAdornmentsThickness ().Vertical;
SuperView.LayoutSubviews ();
private void ClickedInForeground ()
{
if (LineDrawing.PromptForColor ("Foreground", Value.Foreground, out Color newColor))
{
Value = new (newColor, Value.Background);
SetNeedsDisplay ();
}
}
}

View File

@@ -63,55 +63,25 @@ public class ProgressBarStyles : Scenario
#region ColorPicker
ColorName ChooseColor (string text, ColorName colorName)
{
var colorPicker = new ColorPicker { Title = text, SelectedColor = colorName };
var dialog = new Dialog { Title = text };
dialog.Initialized += (sender, args) =>
{
// TODO: Replace with Dim.Auto
dialog.X = _pbList.Frame.X;
dialog.Y = _pbList.Frame.Height;
};
dialog.LayoutComplete += (sender, args) =>
{
dialog.Viewport = Rectangle.Empty with
{
Width = colorPicker.Frame.Width,
Height = colorPicker.Frame.Height
};
Application.Top.LayoutSubviews ();
};
dialog.Add (colorPicker);
colorPicker.ColorChanged += (s, e) => { dialog.RequestStop (); };
Application.Run (dialog);
dialog.Dispose ();
ColorName retColor = colorPicker.SelectedColor;
colorPicker.Dispose ();
return retColor;
}
var fgColorPickerBtn = new Button
{
Text = "Foreground HotNormal Color",
X = Pos.Center (),
Y = Pos.Align (Alignment.Start),
Y = Pos.Align (Alignment.Start)
};
container.Add (fgColorPickerBtn);
fgColorPickerBtn.Accept += (s, e) =>
{
ColorName newColor = ChooseColor (
fgColorPickerBtn.Text,
editor.ViewToEdit.ColorScheme.HotNormal.Foreground
.GetClosestNamedColor ()
);
if (!LineDrawing.PromptForColor (
fgColorPickerBtn.Text,
editor.ViewToEdit.ColorScheme.HotNormal.Foreground,
out var newColor
))
{
return;
}
var cs = new ColorScheme (editor.ViewToEdit.ColorScheme)
{
@@ -134,11 +104,14 @@ public class ProgressBarStyles : Scenario
bgColorPickerBtn.Accept += (s, e) =>
{
ColorName newColor = ChooseColor (
fgColorPickerBtn.Text,
editor.ViewToEdit.ColorScheme.HotNormal.Background
.GetClosestNamedColor ()
);
if (!LineDrawing.PromptForColor (
fgColorPickerBtn.Text,
editor.ViewToEdit.ColorScheme.HotNormal.Background
, out var newColor))
{
return;
}
var cs = new ColorScheme (editor.ViewToEdit.ColorScheme)
{

View File

@@ -318,17 +318,17 @@ public class Shortcuts : Scenario
CanFocus = false
};
var bgColor = new ColorPicker ()
var bgColor = new ColorPicker16 ()
{
CanFocus = false,
BoxHeight = 1,
BoxWidth = 1,
CanFocus = false
};
bgColor.ColorChanged += (o, args) =>
{
Application.Top.ColorScheme = new ColorScheme (Application.Top.ColorScheme)
{
Normal = new Attribute (Application.Top.ColorScheme.Normal.Foreground, args.Color),
Normal = new Attribute (Application.Top.ColorScheme.Normal.Foreground, args.CurrentValue),
};
};
hShortcutBG.CommandView = bgColor;