core/dialog/widget.go
Functions
func Children
func (s *surfaceWidget) Children() []widget.Widget {
return nil
}
func Children
Children returns nil because the dialog's content is rendered via the
overlay surface, not as a direct child.
func (w *Widget) Children() []widget.Widget {
return nil
}
func Close
Close removes the dialog from the overlay stack.
If the dialog is not open, this is a no-op.
func (w *Widget) Close(ctx widget.Context) {
w.doClose(ctx)
}
func Dismiss
Dismiss is called by the overlay stack when the overlay should close.
func (s *surfaceWidget) Dismiss() {
s.dialog.doClose(s.ctx)
}
func Draw
Draw renders the backdrop and dialog surface.
func (s *surfaceWidget) Draw(ctx widget.Context, canvas widget.Canvas) {
if canvas == nil {
return
}
d := s.dialog
// Draw backdrop.
backdropColor := defaultBackdropColor
canvas.DrawRect(s.Bounds(), backdropColor)
// Compute dialog bounds.
windowSize := ctx.WindowSize()
dialogBounds := d.computeDialogBounds(windowSize)
// Delegate to painter for the dialog surface.
d.painter.PaintDialog(canvas, PaintState{
Title: d.cfg.ResolvedTitle(),
HasContent: d.cfg.content != nil,
Actions: d.cfg.actions,
Focused: s.focusIndex >= 0,
Bounds: dialogBounds,
})
// Draw content widget if present.
if d.cfg.content != nil {
contentBounds := geometry.Rect{
Min: geometry.Pt(dialogBounds.Min.X+contentPadding, dialogBounds.Min.Y+titleAreaHeight),
Max: geometry.Pt(dialogBounds.Max.X-contentPadding, dialogBounds.Max.Y-actionAreaHeight),
}
if setter, ok := d.cfg.content.(interface{ SetBounds(geometry.Rect) }); ok {
setter.SetBounds(contentBounds)
}
d.cfg.content.Draw(ctx, canvas)
}
}
func Draw
Draw renders the dialog. When shown as an overlay, drawing is handled
by the surfaceWidget. This is a no-op when hidden.
func (w *Widget) Draw(_ widget.Context, _ widget.Canvas) {
// Rendering is handled by surfaceWidget in the overlay stack.
}
func Event
Event handles input events. When shown as an overlay, events are handled
by the surfaceWidget. This returns false when hidden.
func (w *Widget) Event(_ widget.Context, _ event.Event) bool {
return false
}
func Event
Event handles input events for the dialog overlay.
func (s *surfaceWidget) Event(ctx widget.Context, e event.Event) bool {
switch ev := e.(type) {
case *event.KeyEvent:
return s.handleKeyEvent(ctx, ev)
case *event.MouseEvent:
return s.handleMouseEvent(ctx, ev)
default:
// Modal: consume all events to prevent interaction with background.
return true
}
}
func IsOpen
IsOpen returns true if the dialog is currently visible as an overlay.
func (w *Widget) IsOpen() bool {
return w.visible
}
func Layout
Layout calculates the dialog's preferred size. When shown as an overlay,
layout is handled by the surfaceWidget. This returns zero size when hidden.
func (w *Widget) Layout(_ widget.Context, constraints geometry.Constraints) geometry.Size {
if !w.visible {
return geometry.Size{}
}
return constraints.Constrain(geometry.Sz(defaultMaxWidth, minDialogHeight))
}
func Layout
Layout fills the entire window.
func (s *surfaceWidget) Layout(ctx widget.Context, constraints geometry.Constraints) geometry.Size {
windowSize := ctx.WindowSize()
size := constraints.Constrain(windowSize)
s.SetBounds(geometry.NewRect(0, 0, size.Width, size.Height))
return size
}
func Modal
Modal returns true; dialogs always block interaction with the background.
func (s *surfaceWidget) Modal() bool {
return true
}
func Mount
Mount creates signal bindings for push-based invalidation.
Implements [widget.Lifecycle].
func (w *Widget) Mount(ctx widget.Context) {
sched := ctx.Scheduler()
if sched == nil {
return
}
if w.cfg.readonlyTitleSignal != nil {
b := state.BindToScheduler(w.cfg.readonlyTitleSignal, w, sched)
w.AddBinding(b)
} else if w.cfg.titleSignal != nil {
b := state.BindToScheduler(w.cfg.titleSignal, w, sched)
w.AddBinding(b)
}
}
func New
New creates a new dialog Widget with the given options.
The returned widget is NOT visible until [Widget.Show] is called.
By default, the dialog is dismissible (backdrop click) and closes on Escape.
func New(opts ...Option) *Widget {
w := &Widget{
painter: DefaultPainter{},
}
// Defaults.
w.cfg.dismissible = true
w.cfg.escToClose = true
w.cfg.maxWidth = defaultMaxWidth
for _, opt := range opts {
opt(&w.cfg)
}
if w.cfg.painter != nil {
w.painter = w.cfg.painter
}
w.SetEnabled(true)
return w
}
func Show
Show pushes the dialog as a modal overlay via the context's OverlayManager.
If the dialog is already open, this is a no-op.
func (w *Widget) Show(ctx widget.Context) {
if w.visible {
return
}
om := ctx.OverlayManager()
if om == nil {
return
}
w.visible = true
w.SetVisible(true)
// Create the surface widget for overlay rendering.
w.surface = newSurfaceWidget(w, ctx)
om.PushOverlay(w.surface, func() {
w.doClose(ctx)
})
// ADR-028: visual only — overlay display is handled by DrawOverlays.
w.SetNeedsRedraw(true)
}
func Unmount
Unmount is called when the dialog is removed from the widget tree.
Implements [widget.Lifecycle].
func (w *Widget) Unmount() {
// Bindings are cleaned up automatically by WidgetBase.CleanupBindings().
}
Structs
type Widget struct
Widget implements a modal dialog with title, content, and action buttons.
A dialog is created in a hidden state with [New]. Call [Widget.Show] to
push it as a modal overlay, and [Widget.Close] to remove it.
The dialog renders a semi-transparent backdrop that blocks interaction
with the background, and a centered surface containing the title,
optional content widget, and action buttons.
type Widget struct {
widget.WidgetBase
cfg config
painter Painter
visible bool
// Overlay surface widget manages the dialog surface content.
surface *surfaceWidget
}
Children returns nil; the surface has no child widgets in the tree.