LineDrawing.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Terminal.Gui;
  5. namespace UICatalog.Scenarios;
  6. [ScenarioMetadata ("Line Drawing", "Demonstrates LineCanvas.")]
  7. [ScenarioCategory ("Controls")]
  8. [ScenarioCategory ("Drawing")]
  9. public class LineDrawing : Scenario
  10. {
  11. public override void Setup ()
  12. {
  13. var canvas = new DrawingArea { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
  14. var tools = new ToolsView { Title = "Tools", X = Pos.Right (canvas) - 20, Y = 2 };
  15. tools.ColorChanged += c => canvas.SetColor (c);
  16. tools.SetStyle += b => canvas.LineStyle = b;
  17. tools.AddLayer += () => canvas.AddLayer ();
  18. Win.Add (canvas);
  19. Win.Add (tools);
  20. Win.KeyDown += (s, e) => { e.Handled = canvas.OnKeyDown (e); };
  21. }
  22. private class DrawingArea : View
  23. {
  24. private readonly List<LineCanvas> _layers = new ();
  25. private readonly Stack<StraightLine> _undoHistory = new ();
  26. private Color _currentColor = new (Color.White);
  27. private LineCanvas _currentLayer;
  28. private StraightLine _currentLine;
  29. public DrawingArea () { AddLayer (); }
  30. public LineStyle LineStyle { get; set; }
  31. public override void OnDrawContentComplete (Rectangle contentArea)
  32. {
  33. base.OnDrawContentComplete (contentArea);
  34. foreach (LineCanvas canvas in _layers)
  35. {
  36. foreach (KeyValuePair<Point, Cell> c in canvas.GetCellMap ())
  37. {
  38. Driver.SetAttribute (c.Value.Attribute ?? ColorScheme.Normal);
  39. // TODO: #2616 - Support combining sequences that don't normalize
  40. AddRune (c.Key.X, c.Key.Y, c.Value.Rune);
  41. }
  42. }
  43. }
  44. //// BUGBUG: Why is this not handled by a key binding???
  45. public override bool OnKeyDown (Key e)
  46. {
  47. // BUGBUG: These should be implemented with key bindings
  48. if (e.KeyCode == (KeyCode.Z | KeyCode.CtrlMask))
  49. {
  50. StraightLine pop = _currentLayer.RemoveLastLine ();
  51. if (pop != null)
  52. {
  53. _undoHistory.Push (pop);
  54. SetNeedsDisplay ();
  55. return true;
  56. }
  57. }
  58. if (e.KeyCode == (KeyCode.Y | KeyCode.CtrlMask))
  59. {
  60. if (_undoHistory.Any ())
  61. {
  62. StraightLine pop = _undoHistory.Pop ();
  63. _currentLayer.AddLine (pop);
  64. SetNeedsDisplay ();
  65. return true;
  66. }
  67. }
  68. return false;
  69. }
  70. public override bool OnMouseEvent (MouseEvent mouseEvent)
  71. {
  72. if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
  73. {
  74. if (_currentLine == null)
  75. {
  76. // Mouse pressed down
  77. _currentLine = new StraightLine (
  78. new Point (mouseEvent.X, mouseEvent.Y),
  79. 0,
  80. Orientation.Vertical,
  81. LineStyle,
  82. new Attribute (_currentColor, GetNormalColor ().Background)
  83. );
  84. _currentLayer.AddLine (_currentLine);
  85. }
  86. else
  87. {
  88. // Mouse dragged
  89. Point start = _currentLine.Start;
  90. var end = new Point (mouseEvent.X, mouseEvent.Y);
  91. var orientation = Orientation.Vertical;
  92. int length = end.Y - start.Y;
  93. // if line is wider than it is tall switch to horizontal
  94. if (Math.Abs (start.X - end.X) > Math.Abs (start.Y - end.Y))
  95. {
  96. orientation = Orientation.Horizontal;
  97. length = end.X - start.X;
  98. }
  99. if (length > 0)
  100. {
  101. length++;
  102. }
  103. else
  104. {
  105. length--;
  106. }
  107. _currentLine.Length = length;
  108. _currentLine.Orientation = orientation;
  109. _currentLayer.ClearCache ();
  110. SetNeedsDisplay ();
  111. }
  112. }
  113. else
  114. {
  115. // Mouse released
  116. if (_currentLine != null)
  117. {
  118. if (_currentLine.Length == 0)
  119. {
  120. _currentLine.Length = 1;
  121. }
  122. if (_currentLine.Style == LineStyle.None)
  123. {
  124. // Treat none as eraser
  125. int idx = _layers.IndexOf (_currentLayer);
  126. _layers.Remove (_currentLayer);
  127. _currentLayer = new LineCanvas (
  128. _currentLayer.Lines.Exclude (
  129. _currentLine.Start,
  130. _currentLine.Length,
  131. _currentLine.Orientation
  132. )
  133. );
  134. _layers.Insert (idx, _currentLayer);
  135. }
  136. _currentLine = null;
  137. _undoHistory.Clear ();
  138. SetNeedsDisplay ();
  139. }
  140. }
  141. return base.OnMouseEvent (mouseEvent);
  142. }
  143. internal void AddLayer ()
  144. {
  145. _currentLayer = new LineCanvas ();
  146. _layers.Add (_currentLayer);
  147. }
  148. internal void SetColor (Color c) { _currentColor = c; }
  149. }
  150. private class ToolsView : Window
  151. {
  152. private Button _addLayerBtn;
  153. private ColorPicker _colorPicker;
  154. private RadioGroup _stylePicker;
  155. public ToolsView ()
  156. {
  157. BorderStyle = LineStyle.Dotted;
  158. Border.Thickness = new Thickness (1, 2, 1, 1);
  159. Initialized += ToolsView_Initialized;
  160. }
  161. public event Action AddLayer;
  162. public override void BeginInit ()
  163. {
  164. base.BeginInit ();
  165. _colorPicker = new ColorPicker { X = 0, Y = 0, BoxHeight = 1, BoxWidth = 2 };
  166. _colorPicker.ColorChanged += (s, a) => ColorChanged?.Invoke (a.Color);
  167. _stylePicker = new RadioGroup
  168. {
  169. X = 0, Y = Pos.Bottom (_colorPicker), RadioLabels = Enum.GetNames (typeof (LineStyle)).ToArray ()
  170. };
  171. _stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem); };
  172. _stylePicker.SelectedItem = 1;
  173. _addLayerBtn = new Button { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
  174. _addLayerBtn.Accept += (s, a) => AddLayer?.Invoke ();
  175. Add (_colorPicker, _stylePicker, _addLayerBtn);
  176. }
  177. public event Action<Color> ColorChanged;
  178. public event Action<LineStyle> SetStyle;
  179. private void ToolsView_Initialized (object sender, EventArgs e)
  180. {
  181. LayoutSubviews ();
  182. Width = Math.Max (_colorPicker.Frame.Width, _stylePicker.Frame.Width) + GetAdornmentsThickness ().Horizontal;
  183. Height = _colorPicker.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetAdornmentsThickness ().Vertical;
  184. SuperView.LayoutSubviews ();
  185. }
  186. }
  187. }