123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- namespace Terminal.Gui;
- /// <summary>
- /// Represents a single row/column in a Terminal.Gui rendering surface (e.g. <see cref="LineCanvas"/> and
- /// <see cref="ConsoleDriver"/>).
- /// </summary>
- public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, Rune Rune = default)
- {
- /// <summary>The attributes to use when drawing the Glyph.</summary>
- public Attribute? Attribute { get; set; } = Attribute;
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.Cell"/> has been modified since the
- /// last time it was drawn.
- /// </summary>
- public bool IsDirty { get; set; } = IsDirty;
- private Rune _rune = Rune;
- /// <summary>The character to display. If <see cref="Rune"/> is <see langword="null"/>, then <see cref="Rune"/> is ignored.</summary>
- public Rune Rune
- {
- get => _rune;
- set
- {
- CombiningMarks.Clear ();
- _rune = value;
- }
- }
- private List<Rune> _combiningMarks;
- /// <summary>
- /// The combining marks for <see cref="Rune"/> that when combined makes this Cell a combining sequence. If
- /// <see cref="CombiningMarks"/> empty, then <see cref="CombiningMarks"/> is ignored.
- /// </summary>
- /// <remarks>
- /// Only valid in the rare case where <see cref="Rune"/> is a combining sequence that could not be normalized to a
- /// single Rune.
- /// </remarks>
- internal List<Rune> CombiningMarks
- {
- get => _combiningMarks ?? [];
- private set => _combiningMarks = value ?? [];
- }
- /// <inheritdoc/>
- public override string ToString () { return $"[{Rune}, {Attribute}]"; }
- /// <summary>Converts the string into a <see cref="List{Cell}"/>.</summary>
- /// <param name="str">The string to convert.</param>
- /// <param name="attribute">The <see cref="Gui.ColorScheme"/> to use.</param>
- /// <returns></returns>
- public static List<Cell> ToCellList (string str, Attribute? attribute = null)
- {
- List<Cell> cells = new ();
- foreach (Rune rune in str.EnumerateRunes ())
- {
- cells.Add (new () { Rune = rune, Attribute = attribute });
- }
- return cells;
- }
- /// <summary>
- /// Splits a string into a List that will contain a <see cref="List{Cell}"/> for each line.
- /// </summary>
- /// <param name="content">The string content.</param>
- /// <param name="attribute">The color scheme.</param>
- /// <returns>A <see cref="List{Cell}"/> for each line.</returns>
- public static List<List<Cell>> StringToLinesOfCells (string content, Attribute? attribute = null)
- {
- List<Cell> cells = content.EnumerateRunes ()
- .Select (x => new Cell { Rune = x, Attribute = attribute })
- .ToList ();
- return SplitNewLines (cells);
- }
- /// <summary>Converts a <see cref="Cell"/> generic collection into a string.</summary>
- /// <param name="cells">The enumerable cell to convert.</param>
- /// <returns></returns>
- public static string ToString (IEnumerable<Cell> cells)
- {
- var str = string.Empty;
- foreach (Cell cell in cells)
- {
- str += cell.Rune.ToString ();
- }
- return str;
- }
- /// <summary>Converts a <see cref="List{Cell}"/> generic collection into a string.</summary>
- /// <param name="cellsList">The enumerable cell to convert.</param>
- /// <returns></returns>
- public static string ToString (List<List<Cell>> cellsList)
- {
- var str = string.Empty;
- for (var i = 0; i < cellsList.Count; i++)
- {
- IEnumerable<Cell> cellList = cellsList [i];
- str += ToString (cellList);
- if (i + 1 < cellsList.Count)
- {
- str += Environment.NewLine;
- }
- }
- return str;
- }
- // Turns the string into cells, this does not split the contents on a newline if it is present.
- internal static List<Cell> StringToCells (string str, Attribute? attribute = null)
- {
- List<Cell> cells = [];
- foreach (Rune rune in str.ToRunes ())
- {
- cells.Add (new () { Rune = rune, Attribute = attribute });
- }
- return cells;
- }
- internal static List<Cell> ToCells (IEnumerable<Rune> runes, Attribute? attribute = null)
- {
- List<Cell> cells = new ();
- foreach (Rune rune in runes)
- {
- cells.Add (new () { Rune = rune, Attribute = attribute });
- }
- return cells;
- }
- private static List<List<Cell>> SplitNewLines (List<Cell> cells)
- {
- List<List<Cell>> lines = [];
- int start = 0, i = 0;
- var hasCR = false;
- // ASCII code 13 = Carriage Return.
- // ASCII code 10 = Line Feed.
- for (; i < cells.Count; i++)
- {
- if (cells [i].Rune.Value == 13)
- {
- hasCR = true;
- continue;
- }
- if (cells [i].Rune.Value == 10)
- {
- if (i - start > 0)
- {
- lines.Add (cells.GetRange (start, hasCR ? i - 1 - start : i - start));
- }
- else
- {
- lines.Add (StringToCells (string.Empty));
- }
- start = i + 1;
- hasCR = false;
- }
- }
- if (i - start >= 0)
- {
- lines.Add (cells.GetRange (start, i - start));
- }
- return lines;
- }
- /// <summary>
- /// Splits a rune cell list into a List that will contain a <see cref="List{Cell}"/> for each line.
- /// </summary>
- /// <param name="cells">The cells list.</param>
- /// <returns></returns>
- public static List<List<Cell>> ToCells (List<Cell> cells) { return SplitNewLines (cells); }
- }
|