123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- #nullable enable
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Terminal.Gui;
- using UICatalog;
- using UICatalog.Scenarios;
- /// <summary>
- /// Demonstrates creating and drawing regions through mouse dragging.
- /// </summary>
- [ScenarioMetadata ("Regions", "Region Tester")]
- [ScenarioCategory ("Mouse and Keyboard")]
- [ScenarioCategory ("Drawing")]
- public class RegionScenario : Scenario
- {
- private readonly Region _region = new ();
- private Point? _dragStart;
- private bool _isDragging;
- public Rune? _previewFillRune = Glyphs.Stipple;
- public Rune? _fillRune = Glyphs.Dot;
- private RegionDrawStyles _drawStyle;
- private RegionOp _regionOp;
- public override void Main ()
- {
- Application.Init ();
- Window app = new ()
- {
- Title = GetQuitKeyAndName (),
- TabStop = TabBehavior.TabGroup,
- };
- app.Padding.Thickness = new (1);
- var tools = new ToolsView { Title = "Tools", X = Pos.AnchorEnd (), Y = 2 };
- tools.CurrentAttribute = app.ColorScheme.HotNormal;
- tools.SetStyle += b =>
- {
- _drawStyle = (RegionDrawStyles)b;
- app.SetNeedsDraw();
- };
- tools.RegionOpChanged += (s, e) =>
- {
- _regionOp = e;
- };
- //tools.AddLayer += () => canvas.AddLayer ();
- app.Add (tools);
- // Add drag handling to window
- app.MouseEvent += (s, e) =>
- {
- if (e.Flags.HasFlag (MouseFlags.Button1Pressed))
- {
- if (!e.Flags.HasFlag (MouseFlags.ReportMousePosition))
- { // Start drag
- _dragStart = e.ScreenPosition;
- _isDragging = true;
- }
- else
- {
- // Drag
- if (_isDragging && _dragStart.HasValue)
- {
- app.SetNeedsDraw ();
- }
- }
- }
- if (e.Flags.HasFlag (MouseFlags.Button1Released))
- {
- if (_isDragging && _dragStart.HasValue)
- {
- // Add the new region
- AddRectangleFromPoints (_dragStart.Value, e.ScreenPosition, _regionOp);
- _isDragging = false;
- _dragStart = null;
- }
- app.SetNeedsDraw ();
- }
- };
- // Draw the regions
- app.DrawingContent += (s, e) =>
- {
- // Draw all regions with single line style
- //_region.FillRectangles (_attribute.Value, _fillRune);
- switch (_drawStyle)
- {
- case RegionDrawStyles.FillOnly:
- _region.FillRectangles (tools.CurrentAttribute!.Value, _previewFillRune);
- break;
- case RegionDrawStyles.InnerBoundaries:
- _region.DrawBoundaries (app.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
- _region.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
- break;
- case RegionDrawStyles.OuterBoundary:
- _region.DrawOuterBoundary (app.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
- _region.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
- break;
- }
- // If currently dragging, draw preview rectangle
- if (_isDragging && _dragStart.HasValue)
- {
- Point currentMousePos = Application.GetLastMousePosition ()!.Value;
- var previewRect = GetRectFromPoints (_dragStart.Value, currentMousePos);
- var previewRegion = new Region (previewRect);
- previewRegion.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
- previewRegion.DrawBoundaries (app.LineCanvas, LineStyle.Dashed, new (tools.CurrentAttribute!.Value.Foreground.GetHighlightColor(), tools.CurrentAttribute!.Value.Background));
- }
- };
- Application.Run (app);
- // Clean up
- app.Dispose ();
- Application.Shutdown ();
- }
- private void AddRectangleFromPoints (Point start, Point end, RegionOp op)
- {
- var rect = GetRectFromPoints (start, end);
- var region = new Region (rect);
- _region.Combine (region, op); // Or RegionOp.MinimalUnion if you want minimal rectangles
- }
- private Rectangle GetRectFromPoints (Point start, Point end)
- {
- int left = Math.Min (start.X, end.X);
- int top = Math.Min (start.Y, end.Y);
- int right = Math.Max (start.X, end.X);
- int bottom = Math.Max (start.Y, end.Y);
- // Ensure minimum width and height of 1
- int width = Math.Max (1, right - left + 1);
- int height = Math.Max (1, bottom - top + 1);
- return new Rectangle (left, top, width, height);
- }
- }
- public enum RegionDrawStyles
- {
- FillOnly = 0,
- InnerBoundaries = 1,
- OuterBoundary = 2
- }
- public class ToolsView : Window
- {
- //private Button _addLayerBtn;
- private readonly AttributeView _attributeView = new ();
- private RadioGroup _stylePicker;
- private RegionOpSelector _regionOpSelector;
- public Attribute? CurrentAttribute
- {
- get => _attributeView.Value;
- set => _attributeView.Value = value;
- }
- public ToolsView ()
- {
- BorderStyle = LineStyle.Dotted;
- Border!.Thickness = new (1, 2, 1, 1);
- Height = Dim.Auto ();
- Width = Dim.Auto ();
- }
- //public event Action AddLayer;
- public override void BeginInit ()
- {
- base.BeginInit ();
- _attributeView.ValueChanged += (s, e) => AttributeChanged?.Invoke (this, e);
- _stylePicker = new ()
- {
- Width=Dim.Fill(),
- X = 0, Y = Pos.Bottom (_attributeView) + 1, RadioLabels = Enum.GetNames<RegionDrawStyles> ().Select (n => n = "_" + n).ToArray()
- };
- _stylePicker.BorderStyle = LineStyle.Single;
- _stylePicker.Border.Thickness = new (0, 1, 0, 0);
- _stylePicker.Title = "Draw Style";
- _stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem); };
- _stylePicker.SelectedItem = (int)RegionDrawStyles.FillOnly;
- _regionOpSelector = new ()
- {
- X = 0,
- Y = Pos.Bottom (_stylePicker) + 1
- };
- _regionOpSelector.SelectedItemChanged += (s, a) => { RegionOpChanged?.Invoke (this, a); };
- _regionOpSelector.SelectedItem = RegionOp.MinimalUnion;
- //_addLayerBtn = new () { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
- //_addLayerBtn.Accepting += (s, a) => AddLayer?.Invoke ();
- Add (_attributeView, _stylePicker, _regionOpSelector);//, _addLayerBtn);
- }
- public event EventHandler<Attribute?>? AttributeChanged;
- public event EventHandler<RegionOp>? RegionOpChanged;
- public event Action<LineStyle>? SetStyle;
- }
- public class RegionOpSelector : View
- {
- private RadioGroup _radioGroup;
- public RegionOpSelector ()
- {
- Width = Dim.Auto ();
- Height = Dim.Auto ();
- BorderStyle = LineStyle.Single;
- Border.Thickness = new (0, 1, 0, 0);
- Title = "RegionOp";
- _radioGroup = new ()
- {
- X = 0,
- Y = 0,
- RadioLabels = Enum.GetNames<RegionOp> ().Select (n => n = "_" + n).ToArray ()
- };
- _radioGroup.SelectedItemChanged += (s, a) => { SelectedItemChanged?.Invoke (this, (RegionOp)a.SelectedItem); };
- Add (_radioGroup);
- }
- public event EventHandler<RegionOp>? SelectedItemChanged;
- public RegionOp SelectedItem
- {
- get => (RegionOp)_radioGroup.SelectedItem;
- set => _radioGroup.SelectedItem = (int) value;
- }
- }
- 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 =
- [
- (0, 0), (1, 0), (2, 0),
- (0, 1), (1, 1), (2, 1)
- ];
- private static readonly HashSet<(int, int)> _backgroundPoints =
- [
- (3, 1),
- (1, 2), (2, 2), (3, 2)
- ];
- public AttributeView ()
- {
- Width = Dim.Fill();
- Height = 4;
- BorderStyle = LineStyle.Single;
- Border.Thickness = new (0, 1, 0, 0);
- Title = "Attribute";
- }
- /// <inheritdoc/>
- protected override bool OnDrawingContent ()
- {
- Color fg = Value?.Foreground ?? Color.Black;
- Color bg = Value?.Background ?? Color.Black;
- bool isTransparentFg = fg == GetNormalColor ().Background;
- bool isTransparentBg = bg == GetNormalColor ().Background;
- 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
- {
- rune = (Rune)'█';
- }
- AddRune (point.Item1, point.Item2, rune);
- }
- SetAttribute (new (bg, isTransparentBg ? Color.Gray : bg));
- // Square of background color
- foreach ((int, int) point in _backgroundPoints)
- {
- // Make pattern like this when it is same color as background of control
- /*▓▒
- ▒▓*/
- Rune rune;
- if (isTransparentBg)
- {
- rune = (Rune)(point.Item1 % 2 == point.Item2 % 2 ? '▓' : '▒');
- }
- else
- {
- rune = (Rune)'█';
- }
- AddRune (point.Item1, point.Item2, rune);
- }
- return true;
- }
- /// <inheritdoc/>
- protected override bool OnMouseEvent (MouseEventArgs mouseEvent)
- {
- if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked))
- {
- if (IsForegroundPoint (mouseEvent.Position.X, mouseEvent.Position.Y))
- {
- ClickedInForeground ();
- }
- else if (IsBackgroundPoint (mouseEvent.Position.X, mouseEvent.Position.Y))
- {
- ClickedInBackground ();
- }
- }
- mouseEvent.Handled = true;
- return mouseEvent.Handled;
- }
- 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!.Value.Background, out Color newColor))
- {
- Value = new (Value!.Value.Foreground, newColor);
- SetNeedsDraw ();
- }
- }
- private void ClickedInForeground ()
- {
- if (LineDrawing.PromptForColor ("Foreground", Value!.Value.Foreground, out Color newColor))
- {
- Value = new (newColor, Value!.Value.Background);
- SetNeedsDraw ();
- }
- }
- }
|