primitives/themescope.go

Functions Structs

Functions

func Children

Children returns the child widget, or nil if none.

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
}