Skip to main content

Presenter

Trait Presenter 

Source
pub trait Presenter: Output {
    type SurfaceError: RecoverableError;

    // Required methods
    fn init_surface(
        &mut self,
        window: Arc<dyn WindowHandle>,
    ) -> Result<(), Self::SurfaceError>;
    fn resize_surface(&mut self, width: u32, height: u32);
    fn present(&mut self) -> Result<(), Self::SurfaceError>;
    fn cell_size(&self) -> (u32, u32);

    // Provided methods
    fn scale_factor_changed(&mut self, _scale_factor: f64) { ... }
    fn geometry(&self) -> CellGeometry { ... }
}
Expand description

A renderer that rasterizes grid content and presents it to a window surface.

A supertrait of Output, adding the surface lifecycle (init_surface, resize_surface, present, cell_size) that the event loop drives. Every Presenter implementation is an Output implementation for free: WindowBackend delegates its own Output impl straight through to P: Presenter, with no duplicated method bodies.

§Sub-cell offsets and spill

A Tile’s dx/dy shift its glyph within, and past, its cell. This is a cross-backend rendering contract: the CPU rasterizer (retroglyph-software) and the GPU ones (retroglyph-gl, retroglyph-wgpu) must produce the same pixels, so it is specified here once instead of in mirrored per-backend comments that reference each other (and drift when only one is touched). A Presenter that honors sub-cell offsets must obey all four points:

  • dx/dy are in unscaled font pixels (a presenter multiplies by its own integer scale); negative dx shifts the glyph left, negative dy up.
  • The cell’s background fill is always the full, unshifted cell rectangle. An offset moves only the glyph, never the background.
  • An offset glyph may spill past its cell edge into neighboring cells, and that spill is uniform in all four directions: a glyph pushed right/down onto a later neighbor spills the same way as one pushed left/up onto an earlier neighbor.
  • The mechanism that guarantees that uniformity is a two-pass draw: lay down every cell’s background first, then draw every cell’s (offset) glyph over the result. Interleaving the two per cell would let a later cell’s background overwrite an earlier neighbor’s spilled glyph, breaking spill in the right/down directions only.

The offset application is not shared code: the GPU backends shift a quad’s vertex position in their vertex shader, retroglyph-software shifts origin_x/origin_y in a CPU blit: irreducibly different mechanics that must nonetheless agree on the four points above.

§Examples

use retroglyph_core::backend::{DrawCell, Output};
use retroglyph_core::grid::Size;
use retroglyph_window::{Presenter, WindowHandle};
use std::sync::Arc;

struct NullPresenter;

impl Output for NullPresenter {
    type Error = core::convert::Infallible;

    fn draw_layers<'a, I>(&mut self, _content: I) -> Result<(), Self::Error>
    where
        I: Iterator<Item = DrawCell<'a>>,
    {
        Ok(())
    }

    fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn size(&self) -> Size {
        Size::new(4, 2)
    }

    fn clear(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

impl Presenter for NullPresenter {
    type SurfaceError = core::convert::Infallible;

    fn init_surface(&mut self, _window: Arc<dyn WindowHandle>) -> Result<(), Self::SurfaceError> {
        Ok(())
    }

    fn resize_surface(&mut self, _width: u32, _height: u32) {}

    fn present(&mut self) -> Result<(), Self::SurfaceError> {
        Ok(())
    }

    fn cell_size(&self) -> (u32, u32) {
        (8, 16)
    }
}

Required Associated Types§

Source

type SurfaceError: RecoverableError

Surface lifecycle error (context creation, buffer acquisition, present).

Required Methods§

Source

fn init_surface( &mut self, window: Arc<dyn WindowHandle>, ) -> Result<(), Self::SurfaceError>

Initialize the window surface.

Called once from the loop’s resumed handler. The presenter creates its platform surface (softbuffer surface, wgpu device+surface, GL context) from the raw window/display handles.

§Errors

Returns Self::SurfaceError if surface or context creation from window fails (an unsupported display/window system connection, a missing graphics API, or, on wasm32, a canvas element that can’t be located). Unlike a failed present, the winit driver treats this as fatal rather than retryable: it logs the error and exits the event loop immediately, since there is no surface to draw into and no later hook that calls init_surface again.

Source

fn resize_surface(&mut self, width: u32, height: u32)

Resize the window surface to a new physical pixel size.

Called on every window resize event with width/height already resolved by the caller: for the winit driver (see winit::run::WindowApp::resize_to), that means cols * cell_w x rows * cell_h, where cols/rows are the window’s physical size divided down to whole cells. Any sub-cell remainder is truncated, not centered or cleared: when the window’s physical size isn’t an exact multiple of the cell size, width/height here are the largest whole-cell-multiple that fits, which can be smaller than the window’s actual physical size. The OS window itself is never resized to compensate, so a non-exact-multiple resize leaves a thin strip at the window’s trailing edge outside the surface: retroglyph does not paint or clear that strip; whatever the OS/windowing backend leaves there remains visible until a subsequent resize covers it.

Source

fn present(&mut self) -> Result<(), Self::SurfaceError>

Present the rasterized frame to the window surface.

Called after each app tick. A lost frame is not fatal; the caller logs the error and continues.

§Errors

Returns Self::SurfaceError if the surface buffer can’t be acquired or presented (e.g. context lost on wasm, page flip pending on DRI/KMS).

Source

fn cell_size(&self) -> (u32, u32)

Cell size in physical pixels (width, height).

Physical pixels, not logical/DPI-scaled pixels, and never auto-scaled by this crate for display DPI: see the crate-level “DPI, scale, and the resize contract” docs. A presenter whose cells should grow on a HiDPI display must change what this returns itself (from resize or scale_factor_changed); absent that, it stays constant for the presenter’s lifetime.

(u32, u32) rather than Size because grid coordinates are u16 but pixel arithmetic uses u32 (winit PhysicalSize).

Provided Methods§

Source

fn scale_factor_changed(&mut self, _scale_factor: f64)

Notify the presenter that the window’s scale factor (DPI) changed.

Called when the window moves to a display with a different pixel density, or the system DPI setting changes. The event loop follows this with resize_surface for the window’s new physical size, so this hook only needs to handle DPI-dependent state that isn’t a plain buffer resize (e.g. regenerating a font atlas rasterized for a particular scale).

Defaults to a no-op: presenters whose rasterization doesn’t depend on DPI (like SoftwareRenderer’s integer scale config, set once at construction) need no action here.

Source

fn geometry(&self) -> CellGeometry

This presenter’s cell geometry, as a CellGeometry rather than the raw (width, height) pair cell_size returns.

Lets callers (e.g. winit::run’s cursor/mouse handlers) use CellGeometry::pixel_to_cell directly instead of pairing a raw cell_size() with the translate_pixel_to_cell free function. The default implementation derives a geometry from cell_size at scale 1, clamping each dimension to u8::MAX: exact for presenters whose cell size fits in a u8 (true of every glyph/tile size in practice), lossy only past that, which only affects pixel_to_cell precision for callers that don’t override this method (test doubles, not retroglyph-software/retroglyph-gl, both of which override it to return their real internal geometry).

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§