LineDrawing.cs 8.1 KB

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