mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-02 01:03:29 +01:00
* 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:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user