core/tabview/widget.go

Functions Structs

Functions

func Children

Children returns the content widgets of all tabs.

Only the selected tab's content is laid out and drawn, but all

content widgets are reported for tree traversal purposes.

func (w *Widget) Children() []widget.Widget {
	var children []widget.Widget
	for i := range w.cfg.tabs {
		if w.cfg.tabs[i].Content != nil {
			children = append(children, w.cfg.tabs[i].Content)
		}
	}
	if len(children) == 0 {
		return nil
	}
	return children
}

func Draw

Draw renders the tabview to the canvas.

Only the selected tab's content is drawn (lazy).

func (w *Widget) Draw(ctx widget.Context, canvas widget.Canvas) {
	bounds := w.Bounds()
	if bounds.IsEmpty() {
		return
	}

	// Push transform for local coordinate space (children use local bounds).
	canvas.PushTransform(bounds.Min)

	// Update tab states for the painter.
	selectedIdx := w.cfg.ResolvedSelected()
	w.updateTabStates(selectedIdx)

	// Paint the tab bar.
	w.painter.PaintTabBar(canvas, PaintState{
		Bounds:		w.tabBarBounds,
		Tabs:		w.tabStates,
		SelectedIdx:	selectedIdx,
		Position:	w.cfg.position,
		Focused:	w.IsFocused(),
	})

	// Draw only the selected tab's content.
	if selectedIdx >= 0 && selectedIdx < len(w.cfg.tabs) {
		tab := &w.cfg.tabs[selectedIdx]
		if tab.Content != nil {
			contentBounds := w.contentBounds(bounds.Size())
			canvas.PushClip(contentBounds)
			widget.StampScreenOrigin(tab.Content, canvas)
			tab.Content.Draw(ctx, canvas)
			canvas.PopClip()
		}
	}

	canvas.PopTransform()
}

func Event

Event handles an input event and returns true if consumed.

 

Mouse and wheel event positions are translated from parent-local space

to TabView-local space before hit-testing and child dispatch, matching

the coordinate convention used by [splitview.Widget].

func (w *Widget) Event(ctx widget.Context, e event.Event) bool {
	// Translate mouse events to local coordinates.
	if me, ok := e.(*event.MouseEvent); ok {
		local := *me
		local.Position = me.Position.Sub(w.Bounds().Min)
		return w.handleLocalMouseEvent(ctx, &local)
	}

	// Translate wheel events to local coordinates.
	if we, ok := e.(*event.WheelEvent); ok {
		local := *we
		local.Position = we.Position.Sub(w.Bounds().Min)
		return w.handleLocalWheelEvent(ctx, &local)
	}

	// Non-positional events (keyboard, focus) forward to content first, then handle locally.
	selectedIdx := w.cfg.ResolvedSelected()
	if selectedIdx >= 0 && selectedIdx < len(w.cfg.tabs) {
		tab := &w.cfg.tabs[selectedIdx]
		if tab.Content != nil {
			if tab.Content.Event(ctx, e) {
				return true
			}
		}
	}

	return handleEvent(w, ctx, e)
}

func IsFocusable

IsFocusable reports whether the tabview can currently receive focus.

func (w *Widget) IsFocusable() bool {
	return w.IsVisible() && w.IsEnabled()
}

func Layout

Layout calculates the tabview's preferred size within the given constraints.

Only the selected tab's content is laid out (lazy).

func (w *Widget) Layout(ctx widget.Context, constraints geometry.Constraints) geometry.Size {
	totalSize := constraints.Constrain(geometry.Sz(constraints.MaxWidth, constraints.MaxHeight))

	// Calculate tab bar bounds and individual tab bounds.
	w.computeTabLayout(totalSize)

	// Sync tab states (disabled, closeable, etc.) for event handling.
	w.updateTabStates(w.cfg.ResolvedSelected())

	// Layout only the selected tab's content.
	selectedIdx := w.cfg.ResolvedSelected()
	if selectedIdx >= 0 && selectedIdx < len(w.cfg.tabs) {
		tab := &w.cfg.tabs[selectedIdx]
		if tab.Content != nil {
			contentBounds := w.contentBounds(totalSize)
			contentConstraints := geometry.Tight(contentBounds.Size())
			tab.Content.Layout(ctx, contentConstraints)

			// Set bounds on content widget.
			if setter, ok := tab.Content.(interface{ SetBounds(geometry.Rect) }); ok {
				setter.SetBounds(contentBounds)
			}
		}
	}

	return totalSize
}

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.readonlySelectedSignal != nil {
		b := state.BindToScheduler(w.cfg.readonlySelectedSignal, w, sched)
		w.AddBinding(b)
	} else if w.cfg.selectedSignal != nil {
		b := state.BindToScheduler(w.cfg.selectedSignal, w, sched)
		w.AddBinding(b)
	}
}

func New

New creates a new tabview Widget with the given tabs and options.

 

The returned widget is visible, enabled, and focusable by default.

func New(tabs []Tab, opts ...Option) *Widget {
	w := &Widget{
		painter: DefaultPainter{},
	}
	w.SetVisible(true)
	w.SetEnabled(true)

	// Copy tabs to prevent external mutation.
	w.cfg.tabs = make([]Tab, len(tabs))
	copy(w.cfg.tabs, tabs)

	for _, opt := range opts {
		opt(&w.cfg)
	}

	// Apply painter from config if set.
	if w.cfg.painter != nil {
		w.painter = w.cfg.painter
	}

	// Initialize tab states.
	w.tabStates = make([]TabState, len(tabs))

	// ADR-028: parent chain for upward dirty propagation.
	// Flutter: RenderObject.adoptChild sets parent on each child.
	for i := range w.cfg.tabs {
		if w.cfg.tabs[i].Content != nil {
			type parentSetter interface{ SetParent(widget.Widget) }
			if ps, ok := w.cfg.tabs[i].Content.(parentSetter); ok {
				ps.SetParent(w)
			}
		}
	}

	return w
}

func SelectedIndex

SelectedIndex returns the currently selected tab index.

func (w *Widget) SelectedIndex() int {
	return w.cfg.ResolvedSelected()
}

func TabCount

TabCount returns the number of tabs.

func (w *Widget) TabCount() int {
	return len(w.cfg.tabs)
}

func Unmount

Unmount is called when the tabview 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 tabbed navigation container with configurable appearance.

 

A tabview is created with [New] using functional options:

 

tv := tabview.New(

[]tabview.Tab{

{Label: "Home", Content: homeWidget},

{Label: "Settings", Content: settingsWidget},

},

tabview.PositionOpt(tabview.Top),

tabview.OnSelect(func(idx int) { log.Println("selected:", idx) }),

)

type Widget struct {
	widget.WidgetBase
	cfg	config
	painter	Painter

	// Computed layout state.
	tabBarBounds	geometry.Rect
	tabStates	[]TabState
}