Class: TuiTui::Canvas
- Inherits:
-
Object
- Object
- TuiTui::Canvas
- Defined in:
- lib/tui_tui/canvas.rb
Overview
Pure drawing surface. Coordinates are 1-origin to match terminal cursor addressing, and text layout is terminal-column aware.
Constant Summary collapse
- CONTROL_GLYPH =
Control bytes are rendered visibly instead of being emitted to the terminal.
"?"- FRAME =
Style.new(fg: :bright_black)
Instance Attribute Summary collapse
-
#chrome ⇒ Object
readonly
Returns the value of attribute chrome.
-
#cols ⇒ Object
readonly
Returns the value of attribute cols.
-
#cursor ⇒ Object
readonly
Returns the value of attribute cursor.
-
#rows ⇒ Object
readonly
Returns the value of attribute rows.
Class Method Summary collapse
Instance Method Summary collapse
- #cell(row, col) ⇒ Object
- #cursor_at(row, col) ⇒ Object
- #fill(rect, style, char = " ") ⇒ Object
- #frame(rect, style: FRAME, chrome: @chrome) ⇒ Object
- #grid_row(r) ⇒ Object
- #hline(row, col, len, char = "-", style = nil) ⇒ Object
-
#initialize(rows, cols, chrome: BoxChrome::ASCII) ⇒ Canvas
constructor
A new instance of Canvas.
- #line(row, col, spans) ⇒ Object
- #text(row, col, string, style = nil) ⇒ Object
-
#to_text ⇒ Object
Style-free projection of the grid for snapshot tests: continuation cells of wide glyphs contribute nothing, each row loses its trailing blanks, and rows join with "\n" (no trailing newline).
Constructor Details
#initialize(rows, cols, chrome: BoxChrome::ASCII) ⇒ Canvas
Returns a new instance of Canvas.
26 27 28 29 30 31 32 |
# File 'lib/tui_tui/canvas.rb', line 26 def initialize(rows, cols, chrome: BoxChrome::ASCII) @rows = rows @cols = cols @grid = Array.new(rows) { Array.new(cols, Cell::BLANK) } @cursor = nil @chrome = chrome end |
Instance Attribute Details
#chrome ⇒ Object (readonly)
Returns the value of attribute chrome.
24 25 26 |
# File 'lib/tui_tui/canvas.rb', line 24 def chrome @chrome end |
#cols ⇒ Object (readonly)
Returns the value of attribute cols.
22 23 24 |
# File 'lib/tui_tui/canvas.rb', line 22 def cols @cols end |
#cursor ⇒ Object (readonly)
Returns the value of attribute cursor.
23 24 25 |
# File 'lib/tui_tui/canvas.rb', line 23 def cursor @cursor end |
#rows ⇒ Object (readonly)
Returns the value of attribute rows.
22 23 24 |
# File 'lib/tui_tui/canvas.rb', line 22 def rows @rows end |
Class Method Details
Instance Method Details
#cell(row, col) ⇒ Object
39 40 41 42 43 |
# File 'lib/tui_tui/canvas.rb', line 39 def cell(row, col) return nil unless row.between?(1, @rows) && col.between?(1, @cols) @grid[row - 1][col - 1] end |
#cursor_at(row, col) ⇒ Object
34 35 36 37 |
# File 'lib/tui_tui/canvas.rb', line 34 def cursor_at(row, col) @cursor = [row, col] if row.between?(1, @rows) && col.between?(1, @cols) self end |
#fill(rect, style, char = " ") ⇒ Object
84 85 86 87 88 89 90 91 92 |
# File 'lib/tui_tui/canvas.rb', line 84 def fill(rect, style, char = " ") cell = Cell.new(char: fill_char(char), style: style) rect.rows.times do |dr| row = rect.row + dr rect.cols.times { |dc| place(row, rect.col + dc, cell) } end self end |
#frame(rect, style: FRAME, chrome: @chrome) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/tui_tui/canvas.rb', line 98 def frame(rect, style: FRAME, chrome: @chrome) fill(rect, nil) mid = chrome.h * (rect.cols - 2) text(rect.row, rect.col, chrome.tl + mid + chrome.tr, style) text(rect.row + rect.rows - 1, rect.col, chrome.bl + mid + chrome.br, style) (1...(rect.rows - 1)).each do |dy| text(rect.row + dy, rect.col, chrome.v, style) text(rect.row + dy, rect.col + rect.cols - 1, chrome.v, style) end self end |
#grid_row(r) ⇒ Object
111 |
# File 'lib/tui_tui/canvas.rb', line 111 def grid_row(r) = @grid[r - 1] |
#hline(row, col, len, char = "-", style = nil) ⇒ Object
94 95 96 |
# File 'lib/tui_tui/canvas.rb', line 94 def hline(row, col, len, char = "-", style = nil) text(row, col, char * len, style) end |
#line(row, col, spans) ⇒ Object
74 75 76 77 78 79 80 81 82 |
# File 'lib/tui_tui/canvas.rb', line 74 def line(row, col, spans) column = col spans.each do |span| text(row, column, span.text, span.style) column += DisplayText.new(span.text).width end self end |
#text(row, col, string, style = nil) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/tui_tui/canvas.rb', line 45 def text(row, col, string, style = nil) return self unless row.between?(1, @rows) column = col TextSanitizer.sanitize(string.to_s).each_grapheme_cluster do |grapheme| if Width.control?(grapheme.ord) break if column > @cols place(row, column, Cell.new(char: CONTROL_GLYPH, style: style)) column += 1 next end width = Width.cluster(grapheme) # Leading combining marks have no base cell to attach to. next if width.zero? break if column > @cols # Do not split a wide glyph across the right edge. break if width == 2 && column == @cols place(row, column, Cell.new(char: grapheme, style: style)) place(row, column + 1, Cell.new(char: nil, style: style)) if width == 2 column += width end self end |
#to_text ⇒ Object
Style-free projection of the grid for snapshot tests: continuation cells of wide glyphs contribute nothing, each row loses its trailing blanks, and rows join with "\n" (no trailing newline). Never contains ANSI.
116 117 118 |
# File 'lib/tui_tui/canvas.rb', line 116 def to_text @grid.map { |row| row.filter_map(&:char).join.rstrip }.join("\n") end |