class BBS::Petscii::Canvas
The C64 screen as a grid of 40×25 cells in the uppercase/graphics character set, where the card suits, the balls, the rounded corners, the diagonals and the quarter blocks live. It turns into raw PETSCII: the whole screen once (frame), then only what changes (span, patch, update), because a C64 line behind a modem is slow.
It bypasses the PETSCII Encoder of the session, which speaks the lowercase set: send its bytes with session.write_raw. Its constants are the codes of BBS::Petscii as Integers (there they are Strings, for the Encoder): one code table for both.
A cell is drawn by text from a Unicode string: letters, digits and signs as they are (letters in capitals), and the graphics of GLYPHS and GLYPHS_REVERSED by the character they look like. Colours are the codes (GREEN …) or their names in COLOR_NAMES (:green, +‘light grey’+).
canvas = BBS::Petscii::Canvas.new canvas.text(0, 1, 'TTG CLUBHOUSE', :yellow) canvas.text(2, 1, '╭──╮', :light_blue) session.write_raw(canvas.frame) # the whole screen, once before = canvas.dup canvas.text(2, 2, '●', :red) session.write_raw(canvas.update(before)) # only the changed cell
Byte sizes to aim for on a slow line: a whole screen of art about 1.2 KB, one step of an animation under 200 bytes (update picks the cheaper of a patch and a frame).
Constants
- ASCII_SHOWN
-
The ASCII codes the uppercase set shows as they are (0x5c is £ there, so the backslash is not among them).
- BLACK
-
PETSCII colour code: black.
- BLUE
-
PETSCII colour code: blue.
- BROWN
-
PETSCII colour code: brown.
- CLEAR
-
Control code: clears the screen and homes the cursor.
- COLOR_NAMES
-
The sixteen colours by name, as the C64 calls them.
- COLS
-
The columns of the C64 screen.
- CR
-
Control code: RETURN, the start of the next row with reverse off.
- CYAN
-
PETSCII colour code: cyan.
- Cell
-
One cell: its PETSCII
code, its colour code (nilfor none set) and whether it is in reverse video (rvs). - DARK_GREY
-
PETSCII colour code: dark grey.
- DOWN
-
Control code: the cursor down a row.
- GLYPHS
-
The graphics of the uppercase set by the Unicode character they look like, as PETSCII codes: the shared
BBS::Petscii::GRAPHICSand the set’s ownBBS::Petscii::UPPERCASE_GRAPHICS. - GLYPHS_REVERSED
-
The graphics that are a code of
GLYPHSin reverse video: the full block a reversed space, the upper half a reversed lower half … - GREEN
-
PETSCII colour code: green.
- GREY
-
PETSCII colour code: medium grey.
- HOME
-
Control code: the cursor to the top left.
- LEFT
-
Control code: the cursor left a column.
- LIGHT_BLUE
-
PETSCII colour code: light blue.
- LIGHT_GREEN
-
PETSCII colour code: light green.
- LIGHT_GREY
-
PETSCII colour code: light grey.
- LIGHT_RED
-
PETSCII colour code: light red.
- LOWERCASE
-
Control code: the lowercase character set.
- ORANGE
-
PETSCII colour code: orange.
- PURPLE
-
PETSCII colour code: purple.
- RED
-
PETSCII colour code: red.
- RGB
-
The sixteen colours as [red, green, blue] (the palette of VICE and the C64 wiki, the one the boards match accents against), by code.
- RIGHT
-
Control code: the cursor right a column.
- ROWS
-
The rows of the C64 screen.
- RVS_OFF
-
Control code: reverse video off.
- RVS_ON
-
Control code: reverse video on.
- SPACE
-
The code of a space.
- UP
-
Control code: the cursor up a row.
- UPPERCASE
-
Control code: the uppercase/graphics character set.
- WHITE
-
PETSCII colour code: white.
- YELLOW
-
PETSCII colour code: yellow.
Attributes
The character set the last feed left the screen in: :upper or :lower.
Public Class Methods
Source
# File lib/bbs/petscii/canvas.rb, line 145 def initialize @cells = Array.new(ROWS) { Array.new(COLS) { blank } } @at = [0, 0] @pen = nil @rvs = false @charset = :upper end
Creates an empty screen: every cell a space with no colour.
Public Instance Methods
Source
# File lib/bbs/petscii/canvas.rb, line 195 def cell(row, col) return nil unless row.between?(0, ROWS - 1) && col.between?(0, COLS - 1) @cells[row][col] end
The Cell at row, col, or nil off the screen.
Source
# File lib/bbs/petscii/canvas.rb, line 203 def changes(before) (0...ROWS).flat_map do |row| (0...COLS).filter_map { |col| [row, col] unless @cells[row][col].looks_like?(before.cell(row, col)) } end end
The positions, [row, col] each, where this screen looks different from before (another Canvas): see Cell#looks_like?.
Source
# File lib/bbs/petscii/canvas.rb, line 189 def clear(row, col, width) width.times { |i| @cells[row][col + i] = blank if inside?(row, col + i) } self end
Blanks width cells of row from col. Returns self.
Source
# File lib/bbs/petscii/canvas.rb, line 154 def initialize_copy(source) super @cells = source.cells_copy end
A copy with its own cells, to compare with after drawing (update).
# File lib/bbs/petscii/canvas.rb, line 183 def put(row, col, code, color, rvs: false) @cells[row][col] = Cell.new(code, Canvas.color(color), rvs) if inside?(row, col) self end
Sets the cell at row, col to the PETSCII code as it is, in color (see ::color), reversed with rvs; off the screen, and on the last cell, nothing. Returns self.
# File lib/bbs/petscii/canvas.rb, line 168 def text(row, col, text, color, rvs: false) color = Canvas.color(color) text.each_char.with_index do |ch, i| c = col + i next unless inside?(row, c) code, reversed = Canvas.code(ch) @cells[row][c] = Cell.new(code, color, rvs ^ reversed) end self end
Writes text from row, col (0-based) in color (see ::color; nil sends no colour, so the cell takes the colour printed before it); a character of GLYPHS_REVERSED, or every one with rvs, in reverse video (a reversed glyph with rvs shows plain). Cells off the screen, and the last cell of the last row (printing there scrolls the C64 screen), are left out.
Returns self.
Source
# File lib/bbs/petscii/canvas.rb, line 224 def to_s looks = GLYPHS.invert @cells.map { |row| row.map { |c| looks[c.code] || (c.code < 0x80 ? c.code.chr : '?') }.join.rstrip }.join("\n") end
The screen as text, a line a row, each cell the Unicode character it looks like (a reversed cell as it is printed, not inverted); for tests and logs.
Source
# File lib/bbs/petscii/canvas.rb, line 212 def update(before) changed = changes(before) return ''.b if changed.empty? cheap = patch(changed) whole = frame cheap.bytesize <= whole.bytesize ? cheap : whole end
Protected Instance Methods
Source
# File lib/bbs/petscii/canvas.rb, line 232 def cells_copy = @cells.map { |row| row.map(&:dup) }
A deep copy of the rows of cells.