Documentation
¶
Overview ¶
Package theme holds the colors, text sizes and fonts every UI module reads. Apply changes the global palette under the UI frame lock.
Index ¶
- Constants
- Variables
- func Apply(p Palette)
- func CurrentName() string
- func FetchFonts(urls ...string) error
- func FollowSystemMotion()
- func LoadFontFilesWhere(keep func(font.Font) bool, paths ...string) error
- func LoadFonts(files ...[]byte) error
- func LoadFontsWhere(keep func(font.Font) bool, files ...[]byte) error
- func Names() []string
- func NewShaper(extra ...font.FontFace) *text.Shaper
- func RGB(c uint32) color.NRGBA
- func Register(name string, p Palette)
- func Revision() uint64
- func Scope(p Palette) (restore func())
- func SetReducedMotion(reduce bool)
- func SetSystemReducedMotion(reduce bool)
- func SetSystemScrollbarsAutoHide(hide bool)
- func SystemScrollbarsAutoHide() bool
- func Use(name string) error
- type Elevation
- type FontSet
- type GlyphAtlas
- func (a *GlyphAtlas) BeginFrame(sh *text.Shaper)
- func (a *GlyphAtlas) Commit()
- func (a *GlyphAtlas) Paint(ops *op.Ops, params text.Parameters, gs []text.Glyph, col color.NRGBA)
- func (a *GlyphAtlas) Prepare(params text.Parameters, gs []text.Glyph, col color.NRGBA)
- func (a *GlyphAtlas) Release()
- func (a *GlyphAtlas) ReleaseScratch()
- func (a *GlyphAtlas) Stats() GlyphAtlasStats
- type GlyphAtlasStats
- type GlyphPainter
- type GlyphRenderer
- func (r *GlyphRenderer) BeginFrame(sh *text.Shaper)
- func (r *GlyphRenderer) Commit()
- func (r *GlyphRenderer) Paint(ops *op.Ops, run GlyphRun)
- func (r *GlyphRenderer) Prepare(run GlyphRun)
- func (r *GlyphRenderer) Release()
- func (r *GlyphRenderer) ReleaseScratch()
- func (r *GlyphRenderer) Stats() GlyphAtlasStats
- type GlyphRun
- type Gradient
- type Palette
- type ThemeWatcher
Constants ¶
const ( RadiusSm = 4 // small marks: links, keycaps, compact chips RadiusMd = 6 // controls: buttons, fields, menu items RadiusLg = 8 // cards, popovers, menus, navigation rows RadiusXl = 12 // dialogs, sheets, chat bubbles RadiusFull = 9999 )
Radius steps, in dp. RadiusFull makes a pill or a circle: el clamps a radius to half the shorter side.
const ( TextXs = 11 // axis labels, badges TextSm = 12 // captions, errors, group titles TextMd = 13 // secondary text TextControl = 14 // buttons, tabs, toggles TextBody = 15 // body text TextLg = 17 // panel and dialog titles TextXl = 20 // page titles TextHeading = 22 )
Text size steps, in sp. BodySize, SmallSize and HeadingSize are TextBody, TextMd and TextHeading.
const ( SpaceXxs = 2 // hairline gaps: stacked labels, tight icon pairs SpaceXs = 4 // inside compact controls, between a label and its hint SpaceSm = 6 // between an icon and its text SpaceMd = 8 // between controls in a row, list rows SpaceLg = 12 // control padding, between form fields SpaceXl = 16 // card padding, between groups Space2xl = 24 // dialog and page padding, between sections Space3xl = 32 // between page regions )
Spacing steps, in dp, for gaps, padding and margins. Most layouts need only Xs to Xl; off-scale values are for optical adjustments such as centering an icon.
const ( BodySize unit.Sp = 15 SmallSize unit.Sp = 13 HeadingSize unit.Sp = 22 // ControlHeight is the height of every single-line field: inputs, // selects, pickers and search boxes, so fields side by side line up. ControlHeight unit.Dp = 36 )
Text sizes.
const EmojiFace font.Typeface = "Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, Noto Emoji"
EmojiFace lists platform emoji families for use at the end of a custom typeface list. Naming these explicitly lets common-script emoji reach the system's emoji font instead of an arbitrary missing-glyph fallback. Actual color rendering depends on the font format supported by Gio.
const Face font.Typeface = "PingFang SC, Hiragino Sans GB, Microsoft YaHei, Noto Sans CJK SC, Noto Sans SC, Go, " + EmojiFace
Face lists font families in priority order. Pinning a CJK family avoids tofu from a system fallback font that lacks some simplified Chinese glyphs.
const MonoFace font.Typeface = "SF Mono, Menlo, Cascadia Mono, Consolas, DejaVu Sans Mono, Go Mono, " + Face
MonoFace lists monospaced families for code, numbers in columns and keycaps; CJK falls back to Face's fonts.
Variables ¶
var ( ElevationSm = Elevation{Offset: 1, Blur: 3} // cards that lift on hover ElevationMd = Elevation{Offset: 4, Blur: 12} // popovers, menus, dropdowns, toasts ElevationLg = Elevation{Offset: 12, Blur: 32} // dialogs, sheets, command palette )
Elevation steps: menus and popovers float a little, dialogs more.
var ( Bg = RGB(0xf5f6f8) // window background Surface = RGB(0xffffff) // cards and fields Border = RGB(0xe3e5e8) // borders and dividers Text = RGB(0x1f2328) // body text Muted = RGB(0x6b7280) // secondary text, hints, unchecked icons Primary = RGB(0x2563eb) // primary buttons, links, focus, checked icons DangerText = RGB(0xb91c1c) // danger text on surfaces PrimaryText = RGB(0x1d4ed8) // text on selected surfaces CodeBg = RGB(0xf0f1f3) CodeText = RGB(0x1f2328) PrimaryHover = RGB(0x1d4ed8) DangerHover = RGB(0xb91c1c) SubtleHover = RGB(0xe2e5e9) Success = RGB(0x15803d) // positive status Warning = RGB(0xa16207) // caution status Info = RGB(0x0369a1) // informational status Danger = RGB(0xdc2626) // danger buttons Subtle = RGB(0xeceef1) // secondary buttons OnColor = RGB(0xffffff) // text on Primary and Danger Highlight = RGB(0xdbeafe) // selected rows and options Scrim = color.NRGBA{A: 0x66} // dims the window behind a dialog Shadow = color.NRGBA{R: 0x10, G: 0x18, B: 0x28, A: 0x2e} // tints raised surfaces' shadows // Chart is the categorical order for data series; see Palette.Chart. Chart = Light().Chart // BgGradient and PrimaryGradient are optional; see Palette. BgGradient, PrimaryGradient Gradient )
Colors. Components read them at layout time.
var Material = newMaterial()
Material is the underlying Gio theme: text shaper and icons.
var ReducedMotion bool
ReducedMotion is the effective preference. It follows the system by default; SetReducedMotion gives the application an explicit override.
Functions ¶
func Apply ¶
func Apply(p Palette)
Apply synchronously replaces the global palette and redraws every window. Call before opening windows or from a UI callback under the frame lock. Other goroutines must use core.Update(func() { theme.Apply(p) }). Apply never acquires the frame lock itself, so callbacks cannot deadlock on it. Fonts, the text shaper and the Material pointer remain unchanged.
func CurrentName ¶
func CurrentName() string
CurrentName is the theme last chosen with Use; "light" by default. Apply with an unnamed palette does not change it.
func FetchFonts ¶
FetchFonts is for WebAssembly builds, where it downloads font files with the browser. Elsewhere it returns an error: read the files and LoadFonts.
func FollowSystemMotion ¶
func FollowSystemMotion()
FollowSystemMotion removes the application override and applies the latest system value. Unsupported platforms default to allowing motion.
func LoadFontFilesWhere ¶ added in v0.1.6
LoadFontFilesWhere is LoadFontsWhere for font files by path. A file is mapped into memory rather than read where the system allows, and stays mapped for the process lifetime. Upstream typesetting v0.3.5 still copies font tables and eagerly parses outlines; mapping the source does not eliminate those heap allocations.
func LoadFonts ¶
LoadFonts adds font files (TTF, OTF or TTC collections) to the text shaper and redraws every window. Text picks them by family name from Face, so load a family listed there, such as Noto Sans SC. A web build needs this: the browser gives a WebAssembly app no system fonts, and without a CJK font Chinese shows as boxes. Desktop apps can use it to ship a font.
Call it before window.Main or from a callback; from another goroutine wrap it in core.Update, like Apply.
func LoadFontsWhere ¶ added in v0.1.6
LoadFontsWhere is LoadFonts for the faces keep accepts, and parses only those. The faces may keep referring to files, which must not change. A face parsed holds its tables in memory, megabytes for a CJK one, and a collection such as PingFang.ttc holds two dozen faces of which an app draws one or two: loading all of it costs hundreds of megabytes.
func NewShaper ¶
NewShaper builds an independent shaper with extra faces ahead of the fonts loaded through LoadFonts and the Go fallback fonts. System font fallback follows the same platform defaults as Material.Shaper.
func Register ¶
Register adds a named palette, or replaces one, for Named and Names; an app offers them in its theme picker. Built in: light, dark, nord, paper, solarized-dark, high-contrast and aurora (with gradients).
func Revision ¶
func Revision() uint64
Revision changes whenever Apply replaces the palette. Use it in custom render cache keys. Read under the UI lock, like Current.
func Scope ¶
func Scope(p Palette) (restore func())
Scope sets the palette for a part of the window and returns the function that puts the previous one back. el.Themed uses it around a subtree's Render and paint, so the rest of the window keeps its colors; it does not redraw anything. Call it under the frame lock and always restore.
func SetReducedMotion ¶
func SetReducedMotion(reduce bool)
SetReducedMotion overrides the system preference. Call under the UI frame lock.
func SetSystemReducedMotion ¶
func SetSystemReducedMotion(reduce bool)
SetSystemReducedMotion is the window backend's preference bridge. Native changes are remembered while an application override is active.
func SetSystemScrollbarsAutoHide ¶ added in v0.0.5
func SetSystemScrollbarsAutoHide(hide bool)
SetSystemScrollbarsAutoHide is the window backend's bridge for the platform's "hide scroll bars at rest" setting; el's ScrollbarSystem mode follows it. Safe from any goroutine.
func SystemScrollbarsAutoHide ¶ added in v0.0.5
func SystemScrollbarsAutoHide() bool
SystemScrollbarsAutoHide reports the platform's last known setting.
Types ¶
type Elevation ¶
type Elevation struct{ Offset, Blur float32 }
Elevation is a soft shadow under a raised surface, in dp: Offset moves it down, Blur is how far it fades out. Its color is Shadow.
type FontSet ¶ added in v0.1.6
type FontSet struct {
// contains filtered or unexported fields
}
FontSet is fonts parsed, with a text shaper made for them, ready to put to use. Parsing fonts and making a shaper, which reads the system's font index, takes tens of milliseconds: prepare the set on another goroutine while the window opens, and Use it before the first frame.
func PrepareFontFiles ¶ added in v0.1.6
PrepareFontFiles parses the faces keep accepts of the font files at paths, mapped as LoadFontFilesWhere maps them, and makes a shaper for them and the Go fonts. It touches no shared state: call it from any goroutine.
func (*FontSet) Use ¶ added in v0.1.6
func (s *FontSet) Use()
Use adds the set's fonts, as LoadFonts would, and redraws every window. Call it before window.Main or from a callback; from another goroutine wrap it in core.Update. Its shaper serves when no fonts were loaded before it; otherwise a new one is made with them all.
type GlyphAtlas ¶ added in v0.1.6
type GlyphAtlas struct {
// SubpixelPhases has the same meaning as GlyphPainter.SubpixelPhases.
// Zero preserves the exact horizontal positions.
SubpixelPhases int
// contains filtered or unexported fields
}
GlyphAtlas reuses rasterized vector glyphs in immutable image pages. It is opt-in for single-line text drawn at integral pixel translations, without extra scale or rotation. Complex runs use the normal vector drawing path.
Each frame: BeginFrame, Prepare all runs, Commit, then Paint those runs. Preparing all runs before painting lets each changed page be uploaded once. Cached page pixels are bounded to 8 MiB, masks to 2 MiB and 4096 entries. GPU textures and recent immutable page snapshots add to that memory. Use serially, keep it across frames, and call Release when no longer needed. Do not copy a GlyphAtlas after first use.
func (*GlyphAtlas) BeginFrame ¶ added in v0.1.6
func (a *GlyphAtlas) BeginFrame(sh *text.Shaper)
BeginFrame starts preparing text for a frame. Changing the shaper drops all caches so font glyph IDs cannot be confused with those of the previous one.
func (*GlyphAtlas) Commit ¶ added in v0.1.6
func (a *GlyphAtlas) Commit()
Commit freezes changed image pages. Prepare must not be called again until the next BeginFrame. Existing ImageOps always keep their pixels immutable.
func (*GlyphAtlas) Paint ¶ added in v0.1.6
func (a *GlyphAtlas) Paint(ops *op.Ops, params text.Parameters, gs []text.Glyph, col color.NRGBA)
Paint draws a previously prepared run at the same origin as Shaper.Shape. The caller owns clipping, baseline translation and semantic operations.
func (*GlyphAtlas) Prepare ¶ added in v0.1.6
func (a *GlyphAtlas) Prepare(params text.Parameters, gs []text.Glyph, col color.NRGBA)
Prepare caches the vector glyphs and colors required by a run. params must match the parameters used to shape gs. It may replace the shaper's iterator. Cache limits or an unavailable offscreen GPU leave a run on the vector path.
func (*GlyphAtlas) Release ¶ added in v0.1.6
func (a *GlyphAtlas) Release()
Release frees the scratch GPU and drops cached masks and image pages. The atlas may be used again by calling BeginFrame.
func (*GlyphAtlas) ReleaseScratch ¶ added in v0.1.6
func (a *GlyphAtlas) ReleaseScratch()
ReleaseScratch frees temporary rasterization resources while preserving cached masks and image pages. Call serially after Commit, for example when the UI becomes idle. Future new glyphs recreate the renderer as needed.
func (*GlyphAtlas) Stats ¶ added in v0.1.6
func (a *GlyphAtlas) Stats() GlyphAtlasStats
type GlyphAtlasStats ¶ added in v0.1.6
type GlyphAtlasStats struct {
Masks, MaskBytes, Pages, PageBytes int
RasterDraws, VectorDraws uint64
// MaskBatches counts successful offscreen submissions and readbacks.
MaskBatches uint64
}
GlyphAtlasStats reports retained CPU cache storage and cumulative draws. PageBytes excludes GPU textures and older snapshots referenced by Gio.
type GlyphPainter ¶ added in v0.1.6
type GlyphPainter struct {
// FragmentSize is the maximum number of glyphs per fragment. Zero means two.
// Values are limited to 1–8; smaller fragments reuse more paths but draw more.
FragmentSize int
// SubpixelPhases rounds each glyph's horizontal position inside a
// fragment to 1/SubpixelPhases of a pixel. Zero keeps exact positions.
// Text whose advances are not whole pixels, such as a monospace grid at
// fractional scale, otherwise yields up to 64 phases per glyph: more
// fragments than the cache holds, so paths and their GPU buffers are
// rebuilt every frame. Four phases are visually indistinguishable at
// text sizes. Values are limited to 1–64.
SubpixelPhases int
// contains filtered or unexported fields
}
GlyphPainter paints shaped single-line text using reusable vector fragments. Its zero value is ready to use. Like text.Shaper, it must be used serially. Keep it across frames; caches retain at most 128 styles and 4096 fragments. Do not copy a GlyphPainter after its first use. Complex or overlapping glyphs and translucent colors use a whole-run path.
func (*GlyphPainter) Paint ¶ added in v0.1.6
func (p *GlyphPainter) Paint(ops *op.Ops, sh *text.Shaper, params text.Parameters, gs []text.Glyph, col color.NRGBA)
Paint draws glyphs at the same origin as Shaper.Shape and Shaper.Bitmaps: X is relative to the first glyph and Y is the caller's baseline, not Glyph.Y. params must describe the font and size used to shape glyphs. The caller owns clipping and semantic operations. Paint may replace the shaper's iterator.
type GlyphRenderer ¶ added in v0.1.9
type GlyphRenderer struct {
// contains filtered or unexported fields
}
GlyphRenderer shares bounded glyph caches across changing custom text runs. Keep one per view and use serially: BeginFrame, Prepare all visible runs, Commit, then Paint. Release it when the view closes. Do not copy after use. Integral vertical origins use GlyphAtlas. Horizontal fractions are baked into glyph masks so cached pixels are never resampled. Other origins use vector drawing. Complex runs retain the atlas/painter fallbacks for overlapping ink, combining marks, bidi and translucent colors. Extra caller-applied scale or rotation requires GlyphPainter directly.
func (*GlyphRenderer) BeginFrame ¶ added in v0.1.9
func (r *GlyphRenderer) BeginFrame(sh *text.Shaper)
func (*GlyphRenderer) Commit ¶ added in v0.1.9
func (r *GlyphRenderer) Commit()
func (*GlyphRenderer) Paint ¶ added in v0.1.9
func (r *GlyphRenderer) Paint(ops *op.Ops, run GlyphRun)
func (*GlyphRenderer) Prepare ¶ added in v0.1.9
func (r *GlyphRenderer) Prepare(run GlyphRun)
func (*GlyphRenderer) Release ¶ added in v0.1.9
func (r *GlyphRenderer) Release()
func (*GlyphRenderer) ReleaseScratch ¶ added in v0.1.9
func (r *GlyphRenderer) ReleaseScratch()
ReleaseScratch drops temporary rasterization resources when a view is idle. It preserves prepared masks and image pages. Call after Commit, serially.
func (*GlyphRenderer) Stats ¶ added in v0.1.9
func (r *GlyphRenderer) Stats() GlyphAtlasStats
type GlyphRun ¶ added in v0.1.9
type GlyphRun struct {
Params text.Parameters
Glyphs []text.Glyph
Color color.NRGBA
Position f32.Point
}
GlyphRun describes already-shaped, caller-positioned single-line text. Position is its baseline origin in physical pixels. The caller retains the glyph slice until Paint; shaping, clipping and semantic text remain its job.
type Gradient ¶
Gradient is a linear blend from From to To. Angle is in degrees: 0 runs left to right, 90 top to bottom. The zero Gradient means none.
type Palette ¶
type Palette struct {
PrimaryText, DangerText, CodeBg, CodeText color.NRGBA
Bg, Surface, Border, Text, Muted color.NRGBA
Primary, PrimaryHover, Danger, DangerHover color.NRGBA
Success, Warning, Info color.NRGBA
Subtle, SubtleHover, OnColor, Highlight, Scrim color.NRGBA
// Shadow tints the shadows of raised surfaces (Elevation); dark themes
// need a stronger one to read against a dark background.
Shadow color.NRGBA
// Chart is the categorical order for data series: slot i always means
// series i. Validated for color-vision deficiency against Surface.
Chart [8]color.NRGBA
// BgGradient, when set, paints the window background instead of Bg;
// PrimaryGradient paints primary buttons, progress bars and the user's
// chat bubbles instead of Primary. Bg and Primary stay the solid colors
// for everything else, so set them to a color from the gradient.
BgGradient, PrimaryGradient Gradient
}
Palette contains every global color token. Start from Light or Dark when customizing: Apply replaces all colors, including zero (transparent) values.
func Current ¶
func Current() Palette
Current returns a copy of the current colors. Read it under the UI lock, like the public color variables, or before opening the first window.
func ParseTheme ¶
ParseTheme reads a theme file: a base palette ("light" or "dark", or any registered name) and the colors it changes, by Palette field name in any case, as #rgb, #rgba, #rrggbb or #rrggbbaa. Chart takes up to eight colors; bgGradient and primaryGradient take {"from", "to", "angle"}.
{"name": "Nord", "base": "dark",
"colors": {"bg": "#2e3440", "surface": "#3b4252", "primary": "#88c0d0",
"bgGradient": {"from": "#2e3440", "to": "#3b4252", "angle": 90}}}
type ThemeWatcher ¶
type ThemeWatcher struct {
// contains filtered or unexported fields
}
ThemeWatcher keeps the themes in a directory registered while their files change, e.g. so a designer sees a theme file update the running app.
func WatchThemes ¶
func WatchThemes(dir string, interval time.Duration, onChange func(names []string, err error)) (*ThemeWatcher, error)
WatchThemes registers every *.json theme file in dir now, then checks the directory every interval (default one second) for added, changed or removed files. Changes are registered on the next frame, under the frame lock; if the theme in use (CurrentName) changed, it is applied again. onChange, if set, runs then too with the changed theme names, or with the error of a file that failed to parse; the other files still load.
It polls instead of using file system events, so it needs nothing but the standard library and works the same on every platform.
func (*ThemeWatcher) Stop ¶
func (w *ThemeWatcher) Stop()
Stop ends the watching; registered themes stay.