pub struct Screen { /* private fields */ }Expand description
The grid of cells, and the styles they use.
The style table only grows as cells are written; a screen kept between
frames drops the styles no cell uses any more with
compact_styles (a Painter does it for the
screen it paints with Painter::compact), so a picture whose colours
change every frame does not pile them up.
Implementations§
Source§impl Screen
impl Screen
pub fn new(width: u16, height: u16) -> Screen
Sourcepub fn scrolled(&self) -> &[(Rect, u16)]
pub fn scrolled(&self) -> &[(Rect, u16)]
The scrolls scroll_up made since the last
forget_scrolls: each rectangle and how
many rows it moved up.
Sourcepub fn forget_scrolls(&mut self)
pub fn forget_scrolls(&mut self)
Forget the scrolls made so far: after a frame is painted.
pub fn area(&self) -> Rect
pub fn cell(&self, x: u16, y: u16) -> &Cell
Sourcepub fn get(&self, x: u16, y: u16) -> Option<&Cell>
pub fn get(&self, x: u16, y: u16) -> Option<&Cell>
The cell at x, y, if it is on the screen; its style is
style of its id.
use rich::{Segment, Style};
use rich_ext::surface::{Rect, Screen};
let mut screen = Screen::new(4, 1);
let bold = Style::parse("bold").unwrap();
screen.write_lines(Rect::new(0, 0, 4, 1), &[vec![Segment::new("ab", Some(bold.clone()))]]);
let cell = screen.get(1, 0).unwrap();
assert_eq!((cell.text(), screen.style(cell.style)), ("b", Some(&bold)));
assert!(screen.get(4, 0).is_none());pub fn style(&self, id: StyleId) -> Option<&Style>
Sourcepub fn style_count(&self) -> usize
pub fn style_count(&self) -> usize
How many styles the screen’s table holds, counting “no style”:
what its cells use, and what they used before the last
compact_styles.
Sourcepub fn intern(&mut self, style: Option<&Style>) -> StyleId
pub fn intern(&mut self, style: Option<&Style>) -> StyleId
Intern style for use in this screen’s cells.
Sourcepub fn styles_piled_up(&self) -> bool
pub fn styles_piled_up(&self) -> bool
Whether the style table has grown well past what the cells used
when it was last compacted: time for
compact_styles.
Sourcepub fn compact_styles(&mut self) -> StyleRemap
pub fn compact_styles(&mut self) -> StyleRemap
Drop the styles no cell uses, and renumber the rest. The result maps
the old ids to the new, for whatever kept an id of this screen’s
between frames: a Painter that painted it is moved over with
Painter::remap_styles (or compacts it itself with
Painter::compact). The cells keep their styles; only the ids
change.
use rich::{Color, Style};
use rich_ext::surface::Screen;
let mut screen = Screen::new(2, 1);
for n in 0..=255u8 {
screen.put_rgb(0, 0, '▀', Some([n, 0, 0]), Some([0, 0, n]));
}
assert_eq!(screen.style_count(), 257);
screen.compact_styles();
// "No style" (the blank cell) and the last colour pair.
assert_eq!(screen.style_count(), 2);
let cell = screen.cell(0, 0);
let last = Style::from_color(Some(Color::from_rgb(255, 0, 0)), Some(Color::from_rgb(0, 0, 255)));
assert_eq!(screen.style(cell.style), Some(&last));Sourcepub fn put_rgb(
&mut self,
x: u16,
y: u16,
ch: char,
fg: Option<Rgb>,
bg: Option<Rgb>,
)
pub fn put_rgb( &mut self, x: u16, y: u16, ch: char, fg: Option<Rgb>, bg: Option<Rgb>, )
Set the cell at x, y to ch with foreground fg and background
bg in true colour (either missing), without building a
Segment or, unless the pair is new, a Style: the fast way to
draw a picture a cell at a time (half blocks, quadrants, Braille).
The cell takes the style Style::from_color of the two
Color::from_rgbs would give. Off the
screen, nothing is written.
ch takes one cell: a wide or zero-width character becomes a space,
and a terminal control its visible stand-in (see
control_picture). A wide grapheme the
cell was half of becomes a space.
use rich::{Color, Style};
use rich_ext::surface::Screen;
let mut screen = Screen::new(2, 1);
screen.put_rgb(1, 0, '▀', Some([255, 0, 0]), Some([0, 0, 255]));
let cell = screen.cell(1, 0);
let style = Style::from_color(
Some(Color::from_rgb(255, 0, 0)),
Some(Color::from_rgb(0, 0, 255)),
);
assert_eq!((cell.text(), screen.style(cell.style)), ("▀", Some(&style)));Sourcepub fn put(&mut self, x: u16, y: u16, ch: char, style: StyleId)
pub fn put(&mut self, x: u16, y: u16, ch: char, style: StyleId)
Set the cell at x, y to ch in the style style (an id from
intern on this screen), as
put_rgb does: for many cells in one style,
interned once.
use rich::Style;
use rich_ext::surface::Screen;
let mut screen = Screen::new(3, 1);
let bold = screen.intern(Some(&Style::parse("bold").unwrap()));
for x in 0..3 {
screen.put(x, 0, '#', bold);
}
assert_eq!(screen.plain(), ["###"]);Sourcepub fn write_lines(&mut self, rect: Rect, lines: &[Vec<Segment>])
pub fn write_lines(&mut self, rect: Rect, lines: &[Vec<Segment>])
Write rendered lines into rect, replacing what was there: rows
and columns the lines do not reach are cleared. Terminal controls in
the text become visible symbols; a wide grapheme that would cross
the rectangle’s right edge becomes a space.
Sourcepub fn write_runs<'t, L: AsRef<[TextRun<'t>]>>(
&mut self,
rect: Rect,
lines: &[L],
)
pub fn write_runs<'t, L: AsRef<[TextRun<'t>]>>( &mut self, rect: Rect, lines: &[L], )
The fast path’s write_lines: rows of
TextRuns, each a borrowed text and a style already interned in
this screen, written into rect as write_lines writes the same
text in the same styles, without a Segment or a Style a run.
Rows and columns the runs do not reach are cleared. A run with a
line break falls back to write_lines (its text cannot be one row).
use rich::{Segment, Style};
use rich_ext::frame::StyleId;
use rich_ext::surface::{Rect, Screen, TextRun};
let mut fast = Screen::new(6, 1);
let bold = fast.intern(Some(&Style::parse("bold").unwrap()));
fast.write_runs(
Rect::new(0, 0, 6, 1),
&[vec![TextRun::new("ab", bold), TextRun::new("c", StyleId::NONE)]],
);
// The same cells as rich's path.
let mut slow = Screen::new(6, 1);
slow.write_lines(
Rect::new(0, 0, 6, 1),
&[vec![Segment::new("ab", Some(Style::parse("bold").unwrap())), Segment::new("c", None)]],
);
assert_eq!(fast.lines(), slow.lines());Sourcepub fn underlay(&mut self, x: u16, y: u16, style: &Style)
pub fn underlay(&mut self, x: u16, y: u16, style: &Style)
Lay style under the cell at x, y: it takes what the cell’s own
style leaves unset (a stylesheet’s colours, as CSS inherits them).
Sourcepub fn restyle(&mut self, x: u16, y: u16, style: &Style)
pub fn restyle(&mut self, x: u16, y: u16, style: &Style)
Lay style over the cell at x, y (a selection’s highlight).
Sourcepub fn blit(&mut self, source: &Screen, from: Rect, x: u16, y: u16)
pub fn blit(&mut self, source: &Screen, from: Rect, x: u16, y: u16)
Copy the cells of from in source to this screen at x, y,
clipped to this screen. A wide character cut by either edge of
from, or by this screen’s right edge, becomes a space.
Sourcepub fn scroll_up(&mut self, rect: Rect, rows: u16)
pub fn scroll_up(&mut self, rect: Rect, rows: u16)
Move the rows of rect up by rows, dropping the top ones; the
rows that open at the bottom are cleared.
Sourcepub fn lines(&self) -> Vec<Vec<Segment>>
pub fn lines(&self) -> Vec<Vec<Segment>>
Each row as rendered segments, a run of cells in one style per
segment: what any rich renderer takes, so a frame can be drawn
somewhere else (into a ratatui buffer with rs-rich-ratatui’s
lines_to_buffer, for one).
Sourcepub fn to_svg(&self, options: &SvgOptions<'_>) -> String
pub fn to_svg(&self, options: &SvgOptions<'_>) -> String
The screen as an SVG picture of a terminal, through
Frame::to_svg: each row’s runs of cells in their styles, as wide
as the screen. A screenshot of an app, or a snapshot to review.
use rich::{Segment, Style};
use rich_ext::frame::SvgOptions;
use rich_ext::surface::{Rect, Screen};
let mut screen = Screen::new(20, 3);
let red = Style::parse("bold red").unwrap();
screen.write_lines(Rect::new(0, 0, 20, 1), &[vec![Segment::new("hi", Some(red))]]);
let svg = screen.to_svg(&SvgOptions::default().title("demo"));
assert!(svg.starts_with("<svg"));
assert!(svg.contains("font-weight: bold"));