#nullable disable namespace Terminal.Gui.Views; /// /// Used by to render smbol definitions in a graph, e.g. colors and their meanings /// public class LegendAnnotation : View, IAnnotation { /// Ordered collection of entries that are rendered in the legend. private readonly List> _entries = new (); /// Creates a new empty legend at the empty screen coordinates. public LegendAnnotation () : this (Rectangle.Empty) { } /// Creates a new empty legend at the given screen coordinates. /// /// Defines the area available for the legend to render in (within the graph). This is in /// screen units (i.e. not graph space) /// public LegendAnnotation (Rectangle legendBounds) { X = legendBounds.X; Y = legendBounds.Y; Width = legendBounds.Width; Height = legendBounds.Height; BorderStyle = LineStyle.Single; } /// Returns false i.e. Legends render after series public bool BeforeSeries => false; // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing. /// protected override bool OnDrawingText () { return true; } // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing. /// protected override bool OnClearingViewport () { return true; } /// Draws the Legend and all entries into the area within /// public void Render (GraphView graph) { if (!IsInitialized) { // BUGBUG: We should be getting a visual role here? SetScheme (new () { Normal = Application.Driver?.GetAttribute () ?? Attribute.Default }); graph.Add (this); } if (BorderStyle != LineStyle.None) { // BUGBUG: View code should never call Draw directly. This // BUGBUG: needs to be refactored to decouple. DrawAdornments (); RenderLineCanvas (null); } var linesDrawn = 0; foreach (Tuple entry in _entries) { if (entry.Item1.Color.HasValue) { SetAttribute (entry.Item1.Color.Value); } else { graph.SetDriverColorToGraphColor (); } // add the symbol AddRune (0, linesDrawn, entry.Item1.Rune); // switch to normal coloring (for the text) graph.SetDriverColorToGraphColor (); // add the text Move (1, linesDrawn); string str = TextFormatter.ClipOrPad (entry.Item2, Viewport.Width - 1); Application.Driver?.AddStr (str); linesDrawn++; // Legend has run out of space if (linesDrawn >= Viewport.Height) { break; } } } /// Adds an entry into the legend. Duplicate entries are permissible /// The symbol appearing on the graph that should appear in the legend /// /// Text to render on this line of the legend. Will be truncated if outside of Legend /// /// public void AddEntry (GraphCellToRender graphCellToRender, string text) { _entries.Add (Tuple.Create (graphCellToRender, text)); } }