LegendAnnotation.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #nullable disable
  2. namespace Terminal.Gui.Views;
  3. /// <summary>
  4. /// Used by <see cref="GraphView"/> to render smbol definitions in a graph, e.g. colors and their meanings
  5. /// </summary>
  6. public class LegendAnnotation : View, IAnnotation
  7. {
  8. /// <summary>Ordered collection of entries that are rendered in the legend.</summary>
  9. private readonly List<Tuple<GraphCellToRender, string>> _entries = new ();
  10. /// <summary>Creates a new empty legend at the empty screen coordinates.</summary>
  11. public LegendAnnotation () : this (Rectangle.Empty) { }
  12. /// <summary>Creates a new empty legend at the given screen coordinates.</summary>
  13. /// <param name="legendBounds">
  14. /// Defines the area available for the legend to render in (within the graph). This is in
  15. /// screen units (i.e. not graph space)
  16. /// </param>
  17. public LegendAnnotation (Rectangle legendBounds)
  18. {
  19. X = legendBounds.X;
  20. Y = legendBounds.Y;
  21. Width = legendBounds.Width;
  22. Height = legendBounds.Height;
  23. BorderStyle = LineStyle.Single;
  24. }
  25. /// <summary>Returns false i.e. Legends render after series</summary>
  26. public bool BeforeSeries => false;
  27. // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent
  28. // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing.
  29. /// <inheritdoc/>
  30. protected override bool OnDrawingText () { return true; }
  31. // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent
  32. // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing.
  33. /// <inheritdoc/>
  34. protected override bool OnClearingViewport () { return true; }
  35. /// <summary>Draws the Legend and all entries into the area within <see cref="View.Viewport"/></summary>
  36. /// <param name="graph"></param>
  37. public void Render (GraphView graph)
  38. {
  39. if (!IsInitialized)
  40. {
  41. // BUGBUG: We should be getting a visual role here?
  42. SetScheme (new () { Normal = Application.Driver?.GetAttribute () ?? Attribute.Default });
  43. graph.Add (this);
  44. }
  45. if (BorderStyle != LineStyle.None)
  46. {
  47. // BUGBUG: View code should never call Draw directly. This
  48. // BUGBUG: needs to be refactored to decouple.
  49. DrawAdornments ();
  50. RenderLineCanvas (null);
  51. }
  52. var linesDrawn = 0;
  53. foreach (Tuple<GraphCellToRender, string> entry in _entries)
  54. {
  55. if (entry.Item1.Color.HasValue)
  56. {
  57. SetAttribute (entry.Item1.Color.Value);
  58. }
  59. else
  60. {
  61. graph.SetDriverColorToGraphColor ();
  62. }
  63. // add the symbol
  64. AddRune (0, linesDrawn, entry.Item1.Rune);
  65. // switch to normal coloring (for the text)
  66. graph.SetDriverColorToGraphColor ();
  67. // add the text
  68. Move (1, linesDrawn);
  69. string str = TextFormatter.ClipOrPad (entry.Item2, Viewport.Width - 1);
  70. Application.Driver?.AddStr (str);
  71. linesDrawn++;
  72. // Legend has run out of space
  73. if (linesDrawn >= Viewport.Height)
  74. {
  75. break;
  76. }
  77. }
  78. }
  79. /// <summary>Adds an entry into the legend. Duplicate entries are permissible</summary>
  80. /// <param name="graphCellToRender">The symbol appearing on the graph that should appear in the legend</param>
  81. /// <param name="text">
  82. /// Text to render on this line of the legend. Will be truncated if outside of Legend
  83. /// <see cref="View.Viewport"/>
  84. /// </param>
  85. public void AddEntry (GraphCellToRender graphCellToRender, string text) { _entries.Add (Tuple.Create (graphCellToRender, text)); }
  86. }