pub struct Surface<M: SurfaceModel> { /* private fields */ }Implementations§
Source§impl Surface<Pixels>
impl Surface<Pixels>
Sourcepub fn blit_clipped(
&mut self,
x: i32,
y: i32,
image: Image<'_>,
clip: Area,
blend: bool,
)
pub fn blit_clipped( &mut self, x: i32, y: i32, image: Image<'_>, clip: Area, blend: bool, )
Draws image with its top-left corner at (x, y), clipped to clip
and to the surface: only pixels inside both are written and marked
dirty, so a sprite drawn into a viewport never spills out of it.
With blend each pixel is drawn over what is there with its alpha;
without, it replaces it. A short rgba draws the rows it holds.
Source§impl Surface<Cells>
impl Surface<Cells>
Sourcepub fn put(&mut self, x: u32, y: u32, character: char, style: Style) -> u32
pub fn put(&mut self, x: u32, y: u32, character: char, style: Style) -> u32
Writes one character at (x, y). Returns the columns it took: 1,
2 for a wide character, 0 when nothing was written (out of bounds,
or a character a cell never shows). A wide character that does not
fit before the right edge leaves one empty cell instead (the
viewer would drop it).
Sourcepub fn text(&mut self, x: u32, y: u32, text: &str, style: Style) -> u32
pub fn text(&mut self, x: u32, y: u32, text: &str, style: Style) -> u32
Writes text from (x, y) along one row, grapheme by grapheme,
clipped at the right edge. Returns the columns written. Each
grapheme shows as its first character (see the module docs).
Examples found in repository?
More examples
32 fn frame(&mut self, frame: &Frame) {
33 let second = frame.now_ms() / 1000;
34 if self.shown != Some(second) {
35 self.shown = Some(second);
36 let (cols, _) = self.card.size();
37 let time = format!(
38 "{:02}:{:02}:{:02}",
39 second / 3600 % 24,
40 second / 60 % 60,
41 second % 60
42 );
43 self.card.text(0, 0, &time, Style::fg(Colour::FG).bold());
44 let fraction = (second % 60) as f32 / 60.0;
45 let track = Style::fg(Colour::RECEDE_FG);
46 self.card.bar(
47 Area::new(0, 1, cols, 1),
48 fraction,
49 Style::fg(Colour::ACCENT),
50 track,
51 );
52 // Publishes only the cells that changed.
53 let _ = self.card.commit();
54 }
55 // The next second boundary: an idle viewer wakes once a second.
56 frame.wake_at((second + 1) * 1000);
57 }Sourcepub fn fill(&mut self, rect: Rect, character: char, style: Style)
pub fn fill(&mut self, rect: Rect, character: char, style: Style)
Fills rect with character in style (clipped).
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Empties every cell (theme text on a transparent background). The whole surface is dirty; the previous frame is not copied forward.
Sourcepub fn clear_with(&mut self, style: Style)
pub fn clear_with(&mut self, style: Style)
Empties every cell with style (its background shows).
Source§impl Surface<Pixels>
impl Surface<Pixels>
Sourcepub fn set_pixel(&mut self, x: u32, y: u32, colour: Rgba)
pub fn set_pixel(&mut self, x: u32, y: u32, colour: Rgba)
Sets one pixel (no blending). Outside the surface nothing happens.
Sourcepub fn blend_pixel(&mut self, x: i32, y: i32, colour: Rgba)
pub fn blend_pixel(&mut self, x: i32, y: i32, colour: Rgba)
Draws colour over one pixel with its alpha.
Sourcepub fn pixel(&self, x: u32, y: u32) -> Option<Rgba>
pub fn pixel(&self, x: u32, y: u32) -> Option<Rgba>
The pixel at (x, y) as it will be committed next.
Sourcepub fn clear(&mut self, colour: Rgba)
pub fn clear(&mut self, colour: Rgba)
Fills the whole surface with colour. The previous frame is not
copied forward.
Examples found in repository?
24 fn frame(&mut self, frame: &Frame) {
25 let (w, h) = self.stage.size();
26 if w == 0 || h == 0 {
27 // No pixel geometry yet: a resize will follow.
28 return;
29 }
30 let theme = view::theme();
31 let (fg, bg, accent) = (
32 Rgba::hex(theme.fg),
33 Rgba::hex(theme.bg),
34 Rgba::hex(theme.accent),
35 );
36 let t = (frame.now_ms() % 4000) as f32 / 4000.0;
37
38 // A full repaint: nothing is carried forward from the last frame.
39 self.stage.clear(bg);
40 let panel = Area::new(8, 8, w.saturating_sub(16), h.saturating_sub(16));
41 self.stage
42 .fill_rounded_rect(panel, 12, Rgba::hex(theme.recede_bg));
43 self.stage
44 .rounded_rect(panel, 12, Rgba::hex(theme.recede_fg));
45
46 let (cx, cy) = (w as f32 / 2.0, h as f32 / 2.0);
47 let radius = (w.min(h) / 4) as f32;
48 let angle = t * core::f32::consts::TAU;
49 // `no_std` has no `f32::sin`: the SDK re-exports `libm`. The dot
50 // moves between pixels; the shapes antialias it there.
51 let dot = (
52 cx + radius * libm::cosf(angle),
53 cy + radius * libm::sinf(angle),
54 );
55 self.stage
56 .circle((cx, cy), radius, Rgba::hex(theme.recede_fg));
57 self.stage
58 .line((cx as i32, cy as i32), (dot.0 as i32, dot.1 as i32), accent);
59 self.stage.fill_circle(dot, 6.0, accent);
60
61 let bar = Area::new(24, h as i32 - 40, w.saturating_sub(48), 8);
62 self.stage
63 .bar(bar, t, accent, Rgba::hex(theme.recede_fg).with_alpha(96));
64 self.stage.label(24, 24, "shapes", fg);
65 let _ = self.stage.commit();
66
67 match frame.power() {
68 Power::Mains => frame.request_frame(),
69 Power::SavePower => frame.wake_after(1000),
70 }
71 }Sourcepub fn blit(&mut self, x: i32, y: i32, width: u32, height: u32, rgba: &[u8])
pub fn blit(&mut self, x: i32, y: i32, width: u32, height: u32, rgba: &[u8])
Copies an RGBA8 image of width by height pixels (width * 4
bytes per row) to (x, y), clipped to the surface; no blending. A
short rgba copies the rows it holds. Surface::blit_clipped
clips to a rectangle too and can blend.
Sourcepub fn pixels_mut(&mut self) -> RefMut<'_, [u8]>
pub fn pixels_mut(&mut self) -> RefMut<'_, [u8]>
The whole frame being painted, as RGBA8 bytes, holding what was
last committed. The whole surface is marked dirty; for a small
change prefer the drawing methods or Surface::mark_dirty after
Surface::pixels_untracked. Empty while the surface has no pixels.
Sourcepub fn pixels_untracked(&mut self) -> RefMut<'_, [u8]>
pub fn pixels_untracked(&mut self) -> RefMut<'_, [u8]>
As Surface::pixels_mut, recording nothing: mark what you change
with Surface::mark_dirty.
Sourcepub fn repaint_all(&mut self) -> RefMut<'_, [u8]>
pub fn repaint_all(&mut self) -> RefMut<'_, [u8]>
The whole frame for a full repaint: its contents are stale (what was committed two frames ago), nothing is copied forward, and the whole surface is dirty. The cheapest way to draw an animation that repaints every pixel.
Source§impl<M: SurfaceModel> Surface<M>
impl<M: SurfaceModel> Surface<M>
Sourcepub fn new(id: &str) -> Self
pub fn new(id: &str) -> Self
The manifest’s surface id. Binds at once when the viewer has laid
it out, else on its first crate::Event::Resize.
Examples found in repository?
More examples
Sourcepub fn offscreen(geometry: Geometry) -> Self
pub fn offscreen(geometry: Geometry) -> Self
A surface of the plugin’s own that the host never sees: for tests,
and to draw into a buffer before blitting it. Commits are recorded
(Surface::last_commit) but go nowhere.
Sourcepub fn resize_offscreen(&mut self, geometry: Geometry)
pub fn resize_offscreen(&mut self, geometry: Geometry)
Resizes an offscreen surface as a viewer resize would: a new zeroed region, the next commit fully dirty. No-op for a host surface (the host resizes those).
pub fn id(&self) -> String
Sourcepub fn geometry(&self) -> Option<Geometry>
pub fn geometry(&self) -> Option<Geometry>
The current geometry; None until the viewer lays the surface out.
Sourcepub fn size(&self) -> (u32, u32)
pub fn size(&self) -> (u32, u32)
Width and height in the model’s units: cells, or pixels.
Examples found in repository?
More examples
32 fn frame(&mut self, frame: &Frame) {
33 let second = frame.now_ms() / 1000;
34 if self.shown != Some(second) {
35 self.shown = Some(second);
36 let (cols, _) = self.card.size();
37 let time = format!(
38 "{:02}:{:02}:{:02}",
39 second / 3600 % 24,
40 second / 60 % 60,
41 second % 60
42 );
43 self.card.text(0, 0, &time, Style::fg(Colour::FG).bold());
44 let fraction = (second % 60) as f32 / 60.0;
45 let track = Style::fg(Colour::RECEDE_FG);
46 self.card.bar(
47 Area::new(0, 1, cols, 1),
48 fraction,
49 Style::fg(Colour::ACCENT),
50 track,
51 );
52 // Publishes only the cells that changed.
53 let _ = self.card.commit();
54 }
55 // The next second boundary: an idle viewer wakes once a second.
56 frame.wake_at((second + 1) * 1000);
57 }24 fn frame(&mut self, frame: &Frame) {
25 let (w, h) = self.stage.size();
26 if w == 0 || h == 0 {
27 // No pixel geometry yet: a resize will follow.
28 return;
29 }
30 let theme = view::theme();
31 let (fg, bg, accent) = (
32 Rgba::hex(theme.fg),
33 Rgba::hex(theme.bg),
34 Rgba::hex(theme.accent),
35 );
36 let t = (frame.now_ms() % 4000) as f32 / 4000.0;
37
38 // A full repaint: nothing is carried forward from the last frame.
39 self.stage.clear(bg);
40 let panel = Area::new(8, 8, w.saturating_sub(16), h.saturating_sub(16));
41 self.stage
42 .fill_rounded_rect(panel, 12, Rgba::hex(theme.recede_bg));
43 self.stage
44 .rounded_rect(panel, 12, Rgba::hex(theme.recede_fg));
45
46 let (cx, cy) = (w as f32 / 2.0, h as f32 / 2.0);
47 let radius = (w.min(h) / 4) as f32;
48 let angle = t * core::f32::consts::TAU;
49 // `no_std` has no `f32::sin`: the SDK re-exports `libm`. The dot
50 // moves between pixels; the shapes antialias it there.
51 let dot = (
52 cx + radius * libm::cosf(angle),
53 cy + radius * libm::sinf(angle),
54 );
55 self.stage
56 .circle((cx, cy), radius, Rgba::hex(theme.recede_fg));
57 self.stage
58 .line((cx as i32, cy as i32), (dot.0 as i32, dot.1 as i32), accent);
59 self.stage.fill_circle(dot, 6.0, accent);
60
61 let bar = Area::new(24, h as i32 - 40, w.saturating_sub(48), 8);
62 self.stage
63 .bar(bar, t, accent, Rgba::hex(theme.recede_fg).with_alpha(96));
64 self.stage.label(24, 24, "shapes", fg);
65 let _ = self.stage.commit();
66
67 match frame.power() {
68 Power::Mains => frame.request_frame(),
69 Power::SavePower => frame.wake_after(1000),
70 }
71 }Sourcepub fn request_size(&self, cols: u32, rows: u32) -> Result<()>
pub fn request_size(&self, cols: u32, rows: u32) -> Result<()>
Asks the viewer for cols by rows cells (0: its choice in that
dimension) instead of the manifest’s size; see
Context::request_size.
Sourcepub fn set_label(&self, label: Option<&str>) -> Result<()>
pub fn set_label(&self, label: Option<&str>) -> Result<()>
Sets the short label the viewer shows at the right end of this
surface’s chrome title; see
Context::set_label.
Sourcepub fn set_caret(&self, caret: Option<(u32, u32)>) -> Result<()>
pub fn set_caret(&self, caret: Option<(u32, u32)>) -> Result<()>
Places the viewer’s text cursor at (col, row) of this surface
while it takes keys, or removes it; see
Context::set_caret.
pub fn is_attached(&self) -> bool
Sourcepub fn is_dirty(&self) -> bool
pub fn is_dirty(&self) -> bool
Whether anything was drawn since the last commit (or the next commit is the first at a new size).
Sourcepub fn mark_dirty(&mut self, rect: Rect)
pub fn mark_dirty(&mut self, rect: Rect)
Records a rectangle as changed, after writing through a raw slice.
Sourcepub fn commit(&mut self) -> Result<bool>
pub fn commit(&mut self) -> Result<bool>
Publishes what was drawn since the last commit and switches slots.
Ok(false) when nothing changed (no host call, no frame). The
first commit after a (re)bind covers the whole surface.
Examples found in repository?
More examples
32 fn frame(&mut self, frame: &Frame) {
33 let second = frame.now_ms() / 1000;
34 if self.shown != Some(second) {
35 self.shown = Some(second);
36 let (cols, _) = self.card.size();
37 let time = format!(
38 "{:02}:{:02}:{:02}",
39 second / 3600 % 24,
40 second / 60 % 60,
41 second % 60
42 );
43 self.card.text(0, 0, &time, Style::fg(Colour::FG).bold());
44 let fraction = (second % 60) as f32 / 60.0;
45 let track = Style::fg(Colour::RECEDE_FG);
46 self.card.bar(
47 Area::new(0, 1, cols, 1),
48 fraction,
49 Style::fg(Colour::ACCENT),
50 track,
51 );
52 // Publishes only the cells that changed.
53 let _ = self.card.commit();
54 }
55 // The next second boundary: an idle viewer wakes once a second.
56 frame.wake_at((second + 1) * 1000);
57 }24 fn frame(&mut self, frame: &Frame) {
25 let (w, h) = self.stage.size();
26 if w == 0 || h == 0 {
27 // No pixel geometry yet: a resize will follow.
28 return;
29 }
30 let theme = view::theme();
31 let (fg, bg, accent) = (
32 Rgba::hex(theme.fg),
33 Rgba::hex(theme.bg),
34 Rgba::hex(theme.accent),
35 );
36 let t = (frame.now_ms() % 4000) as f32 / 4000.0;
37
38 // A full repaint: nothing is carried forward from the last frame.
39 self.stage.clear(bg);
40 let panel = Area::new(8, 8, w.saturating_sub(16), h.saturating_sub(16));
41 self.stage
42 .fill_rounded_rect(panel, 12, Rgba::hex(theme.recede_bg));
43 self.stage
44 .rounded_rect(panel, 12, Rgba::hex(theme.recede_fg));
45
46 let (cx, cy) = (w as f32 / 2.0, h as f32 / 2.0);
47 let radius = (w.min(h) / 4) as f32;
48 let angle = t * core::f32::consts::TAU;
49 // `no_std` has no `f32::sin`: the SDK re-exports `libm`. The dot
50 // moves between pixels; the shapes antialias it there.
51 let dot = (
52 cx + radius * libm::cosf(angle),
53 cy + radius * libm::sinf(angle),
54 );
55 self.stage
56 .circle((cx, cy), radius, Rgba::hex(theme.recede_fg));
57 self.stage
58 .line((cx as i32, cy as i32), (dot.0 as i32, dot.1 as i32), accent);
59 self.stage.fill_circle(dot, 6.0, accent);
60
61 let bar = Area::new(24, h as i32 - 40, w.saturating_sub(48), 8);
62 self.stage
63 .bar(bar, t, accent, Rgba::hex(theme.recede_fg).with_alpha(96));
64 self.stage.label(24, 24, "shapes", fg);
65 let _ = self.stage.commit();
66
67 match frame.power() {
68 Power::Mains => frame.request_frame(),
69 Power::SavePower => frame.wake_after(1000),
70 }
71 }Sourcepub fn last_commit(&self) -> Option<CommitInfo>
pub fn last_commit(&self) -> Option<CommitInfo>
What the last commit published.
Sourcepub fn pending_dirty(&self) -> Vec<Rect>
pub fn pending_dirty(&self) -> Vec<Rect>
The rectangles the next commit would send (without the fully dirty first commit’s).
Trait Implementations§
Source§impl<M: SurfaceModel> Drop for Surface<M>
impl<M: SurfaceModel> Drop for Surface<M>
Source§impl Shapes for Surface<Cells>
impl Shapes for Surface<Cells>
Source§fn fill_rect(&mut self, area: Area, ink: Style)
fn fill_rect(&mut self, area: Area, ink: Style)
Full blocks in the style’s foreground. For a background panel use
Surface::fill with a space and a background colour.
Source§fn bar(&mut self, area: Area, fraction: f32, fill: Style, track: Style)
fn bar(&mut self, area: Area, fraction: f32, fill: Style, track: Style)
Full blocks in fill, one eighth block for the partial cell, and
░ in track for the rest.
Source§fn fill_rounded_rect(&mut self, area: Area, radius: u32, ink: Style)
fn fill_rounded_rect(&mut self, area: Area, radius: u32, ink: Style)
Full blocks, with quarter blocks in the corners when radius > 0.
type Ink = Style
Source§fn stroke_rect(&mut self, area: Area, ink: Style)
fn stroke_rect(&mut self, area: Area, ink: Style)
area.Source§fn line(&mut self, from: (i32, i32), to: (i32, i32), ink: Style)
fn line(&mut self, from: (i32, i32), to: (i32, i32), ink: Style)
from to to, both ends included.Source§fn rounded_rect(&mut self, area: Area, radius: u32, ink: Style)
fn rounded_rect(&mut self, area: Area, radius: u32, ink: Style)
area with corners of radius (cells round their
corners with arcs whatever the radius; a zero radius is square).Source§fn circle(&mut self, centre: (f32, f32), radius: f32, ink: Style)
fn circle(&mut self, centre: (f32, f32), radius: f32, ink: Style)
centre, in continuous coordinates: the
unit at (x, y) spans x..x + 1, so (x + 0.5, y + 0.5) is its
centre, and a moving shape can sit between units (pixels antialias
it; cells round to the nearest cell). Cells are about twice as tall
as wide, so in cells the radius counts rows and spans twice as many
columns.Source§fn fill_circle(&mut self, centre: (f32, f32), radius: f32, ink: Style)
fn fill_circle(&mut self, centre: (f32, f32), radius: f32, ink: Style)
Shapes::circle).Source§impl Shapes for Surface<Pixels>
impl Shapes for Surface<Pixels>
type Ink = Rgba
Source§fn stroke_rect(&mut self, area: Area, ink: Rgba)
fn stroke_rect(&mut self, area: Area, ink: Rgba)
area.Source§fn line(&mut self, from: (i32, i32), to: (i32, i32), ink: Rgba)
fn line(&mut self, from: (i32, i32), to: (i32, i32), ink: Rgba)
from to to, both ends included.Source§fn bar(&mut self, area: Area, fraction: f32, fill: Rgba, track: Rgba)
fn bar(&mut self, area: Area, fraction: f32, fill: Rgba, track: Rgba)
area: the left fraction (0 to 1) in
fill, the rest in track. Partial units are shown with eighth
blocks (cells) or coverage (pixels).Source§fn rounded_rect(&mut self, area: Area, radius: u32, ink: Rgba)
fn rounded_rect(&mut self, area: Area, radius: u32, ink: Rgba)
area with corners of radius (cells round their
corners with arcs whatever the radius; a zero radius is square).Source§fn fill_rounded_rect(&mut self, area: Area, radius: u32, ink: Rgba)
fn fill_rounded_rect(&mut self, area: Area, radius: u32, ink: Rgba)
area filled, with corners of radius.Source§fn circle(&mut self, centre: (f32, f32), radius: f32, ink: Rgba)
fn circle(&mut self, centre: (f32, f32), radius: f32, ink: Rgba)
centre, in continuous coordinates: the
unit at (x, y) spans x..x + 1, so (x + 0.5, y + 0.5) is its
centre, and a moving shape can sit between units (pixels antialias
it; cells round to the nearest cell). Cells are about twice as tall
as wide, so in cells the radius counts rows and spans twice as many
columns.Source§fn fill_circle(&mut self, centre: (f32, f32), radius: f32, ink: Rgba)
fn fill_circle(&mut self, centre: (f32, f32), radius: f32, ink: Rgba)
Shapes::circle).