This document captures design and implementation notes for Canvas.
For end-user usage and examples, see Canvas.
Painter draws directly into the current CellBuffer during Render.Canvas : VisualPainter : Delegator<Action<CanvasContext>>
HorizontalAlignment = Align.StretchVerticalAlignment = Align.StretchCanvas does not have intrinsic content size. Its MeasureCore returns:
Min = (0, 0)Natural = (0, 0)Max = (∞, ∞)GrowX = 1 only when HorizontalAlignment == Align.StretchGrowY = 1 only when VerticalAlignment == Align.StretchThis makes Canvas behave like a flexible “fills available space” visual by default, but it can also be constrained
via min/max size like any other visual.
During RenderOverride:
Bounds is empty, does nothing.Painter is null, does nothing.Theme via GetTheme()CanvasStyle via GetStyle<CanvasStyle>()CanvasStyle.ResolveDefaultStyle(theme)CanvasContext and calls the painter callback.Painter is executed inside the normal render tracking context.
If the painter reads bindables/state, those reads will be tracked and changes will automatically schedule repaint.
CanvasContext draws with coordinates relative to the canvas origin:
(0,0) is the top-left cell of the canvas boundsThe framework already establishes clipping to the canvas Bounds before calling RenderOverride, but CanvasContext
also performs explicit bounds checks to keep drawing helpers safe.
CanvasContext is a small helper API around the underlying CellBuffer, providing:
Bounds / SizeClear() / Clear(rune, style)SetPixel(x, y, rune, style) (cell-level draw)DrawLine(...) (diagonal line; Bresenham-style cell rasterization)FillRect(...)DrawBox(...) with LineGlyphs (handles small widths/heights)DrawCircle(...) (midpoint circle algorithm; outlines only)WriteText(...) (clipped to the canvas bounds)The helper methods are intentionally simple, allocation-free, and optimized for small surfaces rather than large framebuffers.
Since there is no retained drawing state, a typical painter starts with ctx.Clear(...) and then redraws the full scene.
Resolved from the environment via CanvasStyle.Key:
DefaultRune (default: '█')DefaultStyle : Style?
theme.ForegroundTextStyle() (draw using “ink” on terminal default background).Tests that lock down current behavior:
src/XenoAtom.Terminal.UI.Tests/CanvasTests.cs
CanvasContext).Painter as the fast/low-overhead default.