widget/canvas.go

Functions Structs Interfaces

Functions

func Float64

Float64 returns the alignment as a float64 value for rendering backends.

Left=0, Center=0.5, Right=1.

func (a TextAlign) Float64() float64 {
	switch a {
	case TextAlignCenter:
		return 0.5
	case TextAlignRight:
		return 1.0
	default:
		return 0.0
	}
}

func Hex

Hex creates a Color from a 24-bit hex value (0xRRGGBB).

 

Example:

 

skyBlue := widget.Hex(0x87CEEB)

coral := widget.Hex(0xFF7F50)

func Hex(hex uint32) Color {
	return Color{
		R:	float32((hex>>16)&0xFF) / colorMax8,
		G:	float32((hex>>8)&0xFF) / colorMax8,
		B:	float32(hex&0xFF) / colorMax8,
		A:	1,
	}
}

func HexA

HexA creates a Color from a 32-bit hex value with alpha (0xRRGGBBAA).

 

Example:

 

semiBlue := widget.HexA(0x0000FF80) // 50% transparent blue

func HexA(hex uint32) Color {
	return Color{
		R:	float32((hex>>24)&0xFF) / colorMax8,
		G:	float32((hex>>16)&0xFF) / colorMax8,
		B:	float32((hex>>8)&0xFF) / colorMax8,
		A:	float32(hex&0xFF) / colorMax8,
	}
}

func IsOpaque

IsOpaque returns true if the color is fully opaque (alpha == 1).

func (c Color) IsOpaque() bool {
	return c.A >= 1.0
}

func IsTransparent

IsTransparent returns true if the color is fully transparent (alpha == 0).

func (c Color) IsTransparent() bool {
	return c.A <= 0.0
}

func Lerp

Lerp returns a color linearly interpolated between c and other.

 

t=0 returns c, t=1 returns other.

 

Example:

 

// Fade from red to blue

mid := widget.ColorRed.Lerp(widget.ColorBlue, 0.5)

func (c Color) Lerp(other Color, t float32) Color {
	return Color{
		R:	c.R + (other.R-c.R)*t,
		G:	c.G + (other.G-c.G)*t,
		B:	c.B + (other.B-c.B)*t,
		A:	c.A + (other.A-c.A)*t,
	}
}

func RGB

RGB creates an opaque Color from red, green, and blue components.

 

All components should be in the range [0, 1].

 

Example:

 

white := widget.RGB(1, 1, 1)

black := widget.RGB(0, 0, 0)

func RGB(r, g, b float32) Color {
	return Color{R: r, G: g, B: b, A: 1}
}

func RGB8

RGB8 creates an opaque Color from 8-bit RGB values (0-255).

 

Example:

 

white := widget.RGB8(255, 255, 255)

func RGB8(r, g, b uint8) Color {
	return Color{
		R:	float32(r) / colorMax8,
		G:	float32(g) / colorMax8,
		B:	float32(b) / colorMax8,
		A:	1,
	}
}

func RGBA

RGBA creates a Color from red, green, blue, and alpha components.

 

All components should be in the range [0, 1].

 

Example:

 

red := widget.RGBA(1, 0, 0, 1) // Solid red

semiRed := widget.RGBA(1, 0, 0, 0.5) // 50% transparent red

func RGBA(r, g, b, a float32) Color {
	return Color{R: r, G: g, B: b, A: a}
}

func RGBA8

RGBA8 creates a Color from 8-bit RGBA values (0-255).

 

Example:

 

red := widget.RGBA8(255, 0, 0, 255)

func RGBA8(r, g, b, a uint8) Color {
	return Color{
		R:	float32(r) / colorMax8,
		G:	float32(g) / colorMax8,
		B:	float32(b) / colorMax8,
		A:	float32(a) / colorMax8,
	}
}

func RGBA8

RGBA8 returns the color as 8-bit RGBA components (0-255).

func (c Color) RGBA8() (r, g, b, a uint8) {
	return uint8(clamp01(c.R) * colorMax8),
		uint8(clamp01(c.G) * colorMax8),
		uint8(clamp01(c.B) * colorMax8),
		uint8(clamp01(c.A) * colorMax8)
}

func String

String returns a human-readable name for the text alignment.

func (a TextAlign) String() string {
	if int(a) < len(textAlignNames) {
		return textAlignNames[a]
	}
	return unknownStr
}

func String

String returns the text mode name.

func (m TextMode) String() string {
	if int(m) >= 0 && int(m) < len(textModeNames) {
		return textModeNames[m]
	}
	return unknownStr
}

func WithAlpha

WithAlpha returns a copy of the color with the given alpha value.

 

Example:

 

semiRed := widget.ColorRed.WithAlpha(0.5)

func (c Color) WithAlpha(a float32) Color {
	return Color{R: c.R, G: c.G, B: c.B, A: a}
}

Structs

type TextStyle struct

TextStyle specifies font properties for styled text rendering.

 

TextStyle is used with [StyledTextDrawer] to render text with custom fonts

loaded through the plugin system or font registry. When FontFamily is empty,

the default embedded Inter font is used.

 

Example:

 

style := widget.TextStyle{

FontFamily: "NotoSansCJK",

FontSize: 16,

Bold: true,

Color: widget.ColorBlack,

Align: widget.TextAlignLeft,

}

type TextStyle struct {
	// FontFamily is the font family name (e.g., "Inter", "NotoSansCJK").
	// Empty string falls back to the default embedded font.
	FontFamily	string

	// FontSize is the font size in logical pixels.
	FontSize	float32

	// Bold selects bold weight (700). When false, regular weight (400) is used.
	Bold	bool

	// Italic selects italic style. When false, normal style is used.
	Italic	bool

	// Color is the text color.
	Color	Color

	// Align controls horizontal text alignment within bounds.
	Align	TextAlign
}

type Color struct

Color represents an RGBA color with float32 components.

 

Each component is in the range [0, 1], where 0 is minimum intensity

and 1 is maximum intensity. For alpha, 0 is fully transparent and

1 is fully opaque.

 

Color values use premultiplied alpha for efficient blending.

type Color struct {
	R, G, B, A float32
}

Interfaces

type Canvas interface

Canvas provides drawing operations for widgets.

 

Canvas is passed to widgets during the Draw phase. It provides methods

for drawing shapes, text, and images. The full implementation will be

in the render package; this is a placeholder interface.

 

Coordinate System:

 

Canvas uses a coordinate system where (0,0) is the top-left corner of

the window, X increases to the right, and Y increases downward.

All coordinates are in logical pixels, which may be scaled for HiDPI displays.

 

Example:

 

func (w *MyWidget) Draw(ctx widget.Context, canvas widget.Canvas) {

// Fill background

canvas.DrawRect(w.Bounds(), widget.ColorWhite)

// Draw border

canvas.StrokeRect(w.Bounds(), widget.ColorBlack, 1.0)

}

 

Thread Safety:

 

Canvas is NOT thread-safe. All drawing operations must occur on the

main/UI thread during the Draw phase.

type Canvas interface {
	// Clear fills the entire canvas with the given color.
	Clear(color Color)

	// DrawRect fills a rectangle with the given color.
	DrawRect(r geometry.Rect, color Color)

	// FillRectDirect fills a rectangle using CPU-only rendering, bypassing
	// the GPU shape accelerator. Used for dirty-region background clearing
	// where GPU acceleration is counterproductive (it blocks the compositor
	// non-MSAA blit-only fast path, causing 10x GPU overhead).
	FillRectDirect(r geometry.Rect, color Color)

	// StrokeRect draws the outline of a rectangle.
	//
	// The strokeWidth specifies the line thickness in logical pixels.
	StrokeRect(r geometry.Rect, color Color, strokeWidth float32)

	// DrawRoundRect fills a rounded rectangle with the given color.
	//
	// The radius specifies the corner radius.
	DrawRoundRect(r geometry.Rect, color Color, radius float32)

	// StrokeRoundRect draws the outline of a rounded rectangle.
	StrokeRoundRect(r geometry.Rect, color Color, radius float32, strokeWidth float32)

	// DrawCircle fills a circle with the given color.
	//
	// The center and radius specify the circle geometry.
	DrawCircle(center geometry.Point, radius float32, color Color)

	// StrokeCircle draws the outline of a circle.
	StrokeCircle(center geometry.Point, radius float32, color Color, strokeWidth float32)

	// StrokeArc draws a circular arc outline from startAngle with the given sweep.
	// Angles are in radians. startAngle=0 is 3 o'clock, positive is counterclockwise.
	// The arc is rendered as a single stroke operation using cubic Bézier curves.
	StrokeArc(center geometry.Point, radius float32, startAngle, sweepAngle float64,
		color Color, strokeWidth float32)

	// DrawLine draws a line between two points.
	DrawLine(from, to geometry.Point, color Color, strokeWidth float32)

	// DrawText draws text within the given bounding rectangle.
	//
	// The fontSize is in logical pixels. The bold flag selects bold weight.
	// The align parameter controls horizontal alignment.
	DrawText(text string, bounds geometry.Rect, fontSize float32, color Color, bold bool, align TextAlign)

	// MeasureText returns the width in pixels of the given text string
	// when rendered at the specified font size and weight.
	// This is essential for accurate cursor positioning in text fields.
	MeasureText(text string, fontSize float32, bold bool) float32

	// DrawImage draws an image at the specified position.
	//
	// The image is drawn with its top-left corner at the given point.
	// The image is composited using source-over blending. This method
	// is used by RepaintBoundary to blit cached subtree renders.
	DrawImage(img image.Image, at geometry.Point)

	// PushClip pushes a clipping rectangle onto the clip stack.
	//
	// All subsequent drawing operations will be clipped to this rectangle
	// intersected with any parent clip rectangles.
	PushClip(r geometry.Rect)

	// PushClipRoundRect pushes a rounded rectangle clipping region.
	//
	// All subsequent drawing operations will be clipped to this rounded
	// rectangle. Uses GPU SDF-based clipping when available (gg.ClipRoundRect).
	PushClipRoundRect(r geometry.Rect, radius float32)

	// PopClip removes the most recently pushed clipping region.
	//
	// Must be called for each PushClip or PushClipRoundRect call.
	PopClip()

	// PushTransform pushes a translation transform onto the transform stack.
	//
	// All subsequent drawing operations will be offset by the given point.
	PushTransform(offset geometry.Point)

	// PopTransform removes the most recently pushed transform.
	//
	// Must be called for each PushTransform call.
	PopTransform()

	// TransformOffset returns the current cumulative transform offset.
	//
	// This is the total translation applied by all PushTransform calls
	// currently on the transform stack.
	TransformOffset() geometry.Point

	// ScreenOriginBase returns the screen-space base offset for this canvas.
	//
	// For the main window canvas this is (0,0). For SceneCanvas inside
	// RepaintBoundary recording, this is the boundary widget's screen position.
	// Without this, PushTransform(-bounds.Min) for local coords makes
	// TransformOffset() return local values, and StampScreenOrigin computes
	// wrong ScreenOrigin → dirty.Collector reports regions at (0,0).
	//
	// Flutter equivalent: PaintingContext.offset in RenderObject.paint().
	ScreenOriginBase() geometry.Point

	// ClipBounds returns the current clip rectangle.
	//
	// This is the intersection of all PushClip/PushClipRoundRect regions
	// currently on the clip stack. Used for viewport culling: containers
	// skip Draw on children whose bounds don't intersect the clip region,
	// preventing offscreen widgets from ticking animations.
	ClipBounds() geometry.Rect

	// ReplayScene renders a previously recorded scene.Scene display list
	// into this canvas. Used by RepaintBoundary to replay cached content
	// without re-executing the child widget's Draw method.
	//
	// For Canvas (gg.Context wrapper): renders the scene via GPU scene
	// renderer, which routes commands through gg.Context's GPU accelerator.
	// For SceneCanvas: merges the child scene into the parent scene via
	// Scene.Append (O(commands), zero re-encoding).
	//
	// If s is nil or empty, this is a no-op.
	ReplayScene(s *scene.Scene)
}

type DamageController interface

DamageController can suppress damage tracking during rendering.

Implemented by render.Canvas for retained-mode optimization.

RepaintBoundary uses this to suppress damage during cached scene replay.

type DamageController interface {
	SetDamageTracking(enabled bool)
}

type BoundaryRecorder interface

BoundaryRecorder is implemented by canvases that record into a boundary's

scene.Scene. When DrawChild encounters a child that IS a boundary, it skips

drawing — the child boundary has its own PictureLayer in the compositor.

 

Flutter equivalent: PaintingContext knows it's recording into a boundary's

PictureRecorder. paintChild checks isRepaintBoundary → appendLayer instead

of painting into the current recorder.

type BoundaryRecorder interface {
	IsBoundaryRecording() bool
}

type ArcStroker interface

ArcStroker is an optional interface for canvases that support styled arc strokes.

Use type assertion to check: if s, ok := canvas.(ArcStroker); ok { ... }

type ArcStroker interface {
	// StrokeArcStyled draws a circular arc with the specified line cap style.
	StrokeArcStyled(center geometry.Point, radius float32, startAngle, sweepAngle float64,
		color Color, strokeWidth float32, lineCap LineCap)
}

type SVGFiller interface

SVGFiller is an optional interface for canvases that support SVG path fill.

Use type assertion to check: if f, ok := canvas.(SVGFiller); ok { ... }

type SVGFiller interface {
	// FillSVGPath fills an SVG path within the given bounds.
	FillSVGPath(svgData string, viewBox float32, bounds geometry.Rect, color Color)
}

type SVGRenderer interface

SVGRenderer is an optional interface for canvases that support full SVG rendering.

Full SVG XML is rasterized to bitmap and drawn at the specified bounds.

type SVGRenderer interface {
	// RenderSVG renders full SVG XML within the given bounds with color override.
	RenderSVG(svgXML []byte, bounds geometry.Rect, color Color)
}

type DeviceScaler interface

DeviceScaler is an optional interface for canvases that support DPI-aware

SVG icon rasterization (ADR-026). When a canvas implements DeviceScaler,

the boundary recording infrastructure sets the display scale factor so

that SVG icons are rasterized at physical pixel size (ceil(logical * scale))

and drawn with an inverse-scale transform for crisp HiDPI rendering.

 

Use type assertion to set the scale after creating a recording canvas:

 

if ds, ok := recorder.(widget.DeviceScaler); ok {

ds.SetDeviceScale(ctx.Scale())

}

 

This follows the Qt6/Chromium/IntelliJ pattern where icon assets are

rendered at the device's native resolution rather than logical pixel size.

type DeviceScaler interface {
	SetDeviceScale(scale float32)
}

type TextModeController interface

TextModeController is an optional interface for canvases that support

explicit text rendering mode control.

 

Use type assertion to check availability:

 

if tc, ok := canvas.(widget.TextModeController); ok {

tc.SetTextMode(widget.TextModeMSDF)

defer tc.SetTextMode(widget.TextModeAuto)

}

 

This is primarily useful during zoom/scale operations where the default

auto-selection may cause atlas pressure (issue #94).

 

On SceneCanvas (RepaintBoundary recording), SetTextMode is a no-op because

scene text uses TagText which handles mode selection at replay time.

type TextModeController interface {
	SetTextMode(mode TextMode)
	TextMode() TextMode
}

type StyledTextDrawer interface

StyledTextDrawer is an optional interface for canvases that support

rendering text with custom fonts from the font registry.

 

Use type assertion to check availability:

 

if sd, ok := canvas.(widget.StyledTextDrawer); ok {

sd.DrawStyledText("Hello", bounds, widget.TextStyle{

FontFamily: "NotoSansCJK",

FontSize: 16,

Color: widget.ColorBlack,

})

width := sd.MeasureStyledText("Hello", widget.TextStyle{

FontFamily: "NotoSansCJK",

FontSize: 16,

})

}

 

Widgets that need custom font support should check for this interface

and fall back to [Canvas.DrawText] when it is not available. This follows

the same optional interface pattern as [ArcStroker], [SVGFiller], and

[TextModeController].

type StyledTextDrawer interface {
	// DrawStyledText draws text within the given bounding rectangle using
	// the font specified in the TextStyle. The font is resolved from the
	// global font registry using CSS weight matching.
	DrawStyledText(text string, bounds geometry.Rect, style TextStyle)

	// MeasureStyledText returns the width in pixels of the given text
	// when rendered with the specified TextStyle.
	MeasureStyledText(text string, style TextStyle) float32
}