primitives/themescope.go
Functions
func Children
func (ts *ThemeScopeWidget) Children() []widget.Widget {
if ts.child == nil {
return nil
}
return []widget.Widget{ts.child}
}
func Cursor
func (c *themeScopeContext) Cursor() widget.CursorType { return c.parent.Cursor() }
func DeltaTime
func (c *themeScopeContext) DeltaTime() time.Duration { return c.parent.DeltaTime() }
func Draw
Draw renders the child with the scoped theme context.
func (ts *ThemeScopeWidget) Draw(ctx widget.Context, canvas widget.Canvas) {
if !ts.IsVisible() {
return
}
if ts.child == nil {
return
}
scoped := ts.scopedContext(ctx)
canvas.PushTransform(ts.Bounds().Min)
widget.StampScreenOrigin(ts.child, canvas)
ts.child.Draw(scoped, canvas)
canvas.PopTransform()
}
func Event
Event dispatches events to the child with the scoped theme context.
func (ts *ThemeScopeWidget) Event(ctx widget.Context, e event.Event) bool {
if !ts.IsVisible() || !ts.IsEnabled() {
return false
}
if ts.child == nil {
return false
}
scoped := ts.scopedContext(ctx)
// Translate mouse events to local coordinates.
if me, ok := e.(*event.MouseEvent); ok {
local := *me
local.Position = me.Position.Sub(ts.Bounds().Min)
return ts.child.Event(scoped, &local)
}
return ts.child.Event(scoped, e)
}
func FocusedWidget
func (c *themeScopeContext) FocusedWidget() widget.Widget { return c.parent.FocusedWidget() }
func Invalidate
func (c *themeScopeContext) Invalidate() { c.parent.Invalidate() }
func InvalidateRect
func (c *themeScopeContext) InvalidateRect(r geometry.Rect) { c.parent.InvalidateRect(r) }
func IsFocused
func (c *themeScopeContext) IsFocused(w widget.Widget) bool { return c.parent.IsFocused(w) }
func Layout
Layout delegates sizing to the child widget, passing a context with
the overridden theme.
func (ts *ThemeScopeWidget) Layout(ctx widget.Context, constraints geometry.Constraints) geometry.Size {
scoped := ts.scopedContext(ctx)
if ts.child == nil {
size := constraints.Constrain(geometry.Sz(0, 0))
ts.SetBounds(geometry.FromPointSize(ts.Position(), size))
return size
}
size := ts.child.Layout(scoped, constraints)
// Position the child at origin (no offset).
ts.child.(interface{ SetBounds(geometry.Rect) }).SetBounds(
geometry.FromPointSize(geometry.Pt(0, 0), size),
)
ts.SetBounds(geometry.FromPointSize(ts.Position(), size))
return size
}
func Now
func (c *themeScopeContext) Now() time.Time { return c.parent.Now() }
func OverlayManager
func (c *themeScopeContext) OverlayManager() widget.OverlayManager {
return c.parent.OverlayManager()
}
func ReleaseFocus
func (c *themeScopeContext) ReleaseFocus(w widget.Widget) { c.parent.ReleaseFocus(w) }
func RequestFocus
func (c *themeScopeContext) RequestFocus(w widget.Widget) { c.parent.RequestFocus(w) }
func Scale
func (c *themeScopeContext) Scale() float32 { return c.parent.Scale() }
func Scheduler
func (c *themeScopeContext) Scheduler() widget.SchedulerRef { return c.parent.Scheduler() }
func SetCursor
func (c *themeScopeContext) SetCursor(cursor widget.CursorType) { c.parent.SetCursor(cursor) }
func SetTheme
SetTheme changes the scoped theme.
func (ts *ThemeScopeWidget) SetTheme(theme widget.ThemeProvider) {
ts.theme = theme
}
func Theme
Theme returns the ThemeProvider set on this scope.
func (ts *ThemeScopeWidget) Theme() widget.ThemeProvider {
return ts.theme
}
func ThemeProvider
ThemeProvider returns the overridden theme instead of the parent's theme.
func (c *themeScopeContext) ThemeProvider() widget.ThemeProvider {
return c.theme
}
func ThemeScope
ThemeScope creates a new ThemeScopeWidget that overrides the theme for
the given children.
If multiple children are provided, they are wrapped in a Box container
for vertical layout. A single child is used directly. If no children
are provided, the scope has no child and reports zero size.
The theme parameter must not be nil; passing nil causes ThemeScope to
behave as if no theme override is applied (the parent context theme
is used).
func ThemeScope(theme widget.ThemeProvider, children ...widget.Widget) *ThemeScopeWidget {
ts := &ThemeScopeWidget{
theme: theme,
}
ts.SetVisible(true)
ts.SetEnabled(true)
switch len(children) {
case 0:
// No child.
case 1:
ts.child = children[0]
default:
ts.child = Box(children...)
}
// ADR-028: parent chain for upward dirty propagation.
// Flutter: RenderObject.adoptChild sets parent on each child.
if ts.child != nil {
type parentSetter interface{ SetParent(widget.Widget) }
if ps, ok := ts.child.(parentSetter); ok {
ps.SetParent(ts)
}
}
return ts
}
func WindowSize
func (c *themeScopeContext) WindowSize() geometry.Size { return c.parent.WindowSize() }
Structs
type ThemeScopeWidget struct
ThemeScopeWidget overrides the theme for a subtree of widgets.
All descendants of a ThemeScopeWidget receive the scoped ThemeProvider
instead of the application-level theme. This enables use cases like a
dark dialog inside a light application, a branded section, or a
high-contrast widget region.
ThemeScopeWidget is transparent to layout: it delegates sizing entirely
to its single child. If the scope has no child, it reports zero size.
Nested ThemeScopeWidgets follow the "nearest wins" rule, matching the
Flutter InheritedWidget pattern. The priority chain is:
Widget override > Nearest ThemeScope > App theme > Default
Create a ThemeScopeWidget with the [ThemeScope] constructor.
Example:
darkTheme := material3.NewDark(widget.Hex(0x6750A4))
scoped := primitives.ThemeScope(darkTheme,
primitives.Text("Dark text"),
primitives.Box(
primitives.Text("Also dark"),
).Padding(8),
)
type ThemeScopeWidget struct {
widget.WidgetBase
theme widget.ThemeProvider
child widget.Widget
}
Children returns the child widget, or nil if none.