core/docking/host.go

Functions Structs

Functions

func ActivePanelIndex

ActivePanelIndex returns the active tab index for the given zone.

Returns -1 if the zone is empty.

func (h *Host) ActivePanelIndex(zone Zone) int {
	if int(zone) >= zoneCount || h.zones[zone].isEmpty() {
		return -1
	}
	return h.zones[zone].activeIdx
}

func BottomRatio

BottomRatio sets the size ratio of the bottom zone (0.0 to 1.0).

Default is 0.2 (20% of available height).

func BottomRatio(r float32) HostOption {
	return func(c *hostConfig) { c.bottomRatio = clampRatio(r) }
}

func CenterContent

CenterContent sets the main content widget displayed in the center zone.

func CenterContent(w widget.Widget) HostOption {
	return func(c *hostConfig) { c.centerContent = w }
}

func Children

Children returns all visible content widgets (zone panels + center).

func (h *Host) Children() []widget.Widget {
	var children []widget.Widget

	// Center content.
	if h.cfg.centerContent != nil {
		children = append(children, h.cfg.centerContent)
	}

	// Active panel content from each zone.
	for z := Zone(0); z < zoneCount; z++ {
		if z == Center {
			continue
		}
		panel := h.zones[z].activePanel()
		if panel != nil && panel.Content() != nil {
			children = append(children, panel.Content())
		}
	}

	if len(children) == 0 {
		return nil
	}
	return children
}

func ColorSchemeOpt

ColorSchemeOpt sets the theme-derived color scheme for the dock host.

func ColorSchemeOpt(cs ZoneColorScheme) HostOption {
	return func(c *hostConfig) { c.colorScheme = cs }
}

func Dock

Dock adds a panel to the specified zone.

If the zone already has panels, the new panel becomes an additional tab.

The new panel becomes the active tab in its zone.

func (h *Host) Dock(panel *Panel, zone Zone) {
	if panel == nil {
		return
	}
	if int(zone) >= zoneCount {
		return
	}

	// Remove from any existing zone first.
	h.undockFromAll(panel)

	h.zones[zone].addPanel(panel)

	// ADR-028: parent chain for upward dirty propagation.
	if content := panel.Content(); content != nil {
		type parentSetter interface{ SetParent(widget.Widget) }
		if ps, ok := content.(parentSetter); ok {
			ps.SetParent(h)
		}
	}
}

func Draw

Draw renders the dock layout to the canvas.

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

	// Draw center content first (background).
	if h.cfg.centerContent != nil {
		h.cfg.centerContent.Draw(ctx, canvas)
	}

	// Draw edge zones on top of center.
	for z := Zone(0); z < zoneCount; z++ {
		if z == Center || h.zones[z].isEmpty() {
			continue
		}
		h.drawZone(ctx, canvas, z)
	}
}

func Event

Event handles input events for the dock host.

func (h *Host) Event(ctx widget.Context, e event.Event) bool {
	// Check edge zone tab bars for click events.
	if consumed := h.handleZoneTabEvents(ctx, e); consumed {
		return true
	}

	// Forward to active panel content in edge zones.
	for z := Zone(0); z < zoneCount; z++ {
		if z == Center {
			continue
		}
		panel := h.zones[z].activePanel()
		if panel != nil && panel.Content() != nil {
			if panel.Content().Event(ctx, e) {
				return true
			}
		}
	}

	// Forward to center content.
	if h.cfg.centerContent != nil {
		if h.cfg.centerContent.Event(ctx, e) {
			return true
		}
	}

	return false
}

func Layout

Layout calculates zone sizes and positions all children.

func (h *Host) Layout(ctx widget.Context, constraints geometry.Constraints) geometry.Size {
	totalSize := constraints.Constrain(geometry.Sz(constraints.MaxWidth, constraints.MaxHeight))
	if totalSize.Width <= 0 || totalSize.Height <= 0 {
		totalSize = geometry.Sz(defaultHostWidth, defaultHostHeight)
	}

	origin := h.Bounds().Min
	rects := h.computeZoneRects(totalSize, origin)

	// Layout zone contents.
	for z := Zone(0); z < zoneCount; z++ {
		h.zones[z].bounds = rects[z]
		h.layoutZone(ctx, z, rects[z])
	}

	// Layout center content.
	if h.cfg.centerContent != nil {
		centerRect := rects[Center]
		cc := geometry.Tight(centerRect.Size())
		h.cfg.centerContent.Layout(ctx, cc)
		if setter, ok := h.cfg.centerContent.(interface{ SetBounds(geometry.Rect) }); ok {
			setter.SetBounds(centerRect)
		}
	}

	return totalSize
}

func LeftRatio

LeftRatio sets the size ratio of the left zone (0.0 to 1.0).

Default is 0.2 (20% of available width).

func LeftRatio(r float32) HostOption {
	return func(c *hostConfig) { c.leftRatio = clampRatio(r) }
}

func MovePanel

MovePanel moves a panel from its current zone to a new zone.

Returns true if the panel was found and moved.

func (h *Host) MovePanel(panel *Panel, targetZone Zone) bool {
	if panel == nil || int(targetZone) >= zoneCount {
		return false
	}

	// Find current zone.
	found := false
	for z := Zone(0); z < zoneCount; z++ {
		if h.zones[z].containsPanel(panel) {
			found = true
			break
		}
	}
	if !found {
		return false
	}

	h.undockFromAll(panel)
	h.zones[targetZone].addPanel(panel)
	return true
}

func NewHost

NewHost creates a new dock host with the given options.

 

The returned widget is visible and enabled by default.

func NewHost(opts ...HostOption) *Host {
	h := &Host{
		painter: DefaultPainter{},
	}
	h.SetVisible(true)
	h.SetEnabled(true)

	h.cfg.leftRatio = defaultEdgeRatio
	h.cfg.rightRatio = defaultEdgeRatio
	h.cfg.topRatio = defaultEdgeRatio
	h.cfg.bottomRatio = defaultEdgeRatio

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

	if h.cfg.painter != nil {
		h.painter = h.cfg.painter
	}

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

	return h
}

func OnPanelClose

OnPanelClose sets the callback invoked when a panel's close button is clicked.

The callback receives the panel and the zone it belonged to.

func OnPanelClose(fn func(panel *Panel, zone Zone)) HostOption {
	return func(c *hostConfig) { c.onPanelClose = fn }
}

func PainterOpt

PainterOpt sets the painter used to render zone borders and tab headers.

If not set, [DefaultPainter] is used.

func PainterOpt(p Painter) HostOption {
	return func(c *hostConfig) { c.painter = p }
}

func PanelCount

PanelCount returns the number of panels in the given zone.

func (h *Host) PanelCount(zone Zone) int {
	if int(zone) >= zoneCount {
		return 0
	}
	return len(h.zones[zone].panels)
}

func PanelZone

PanelZone returns the zone a panel is docked to, and whether it was found.

func (h *Host) PanelZone(panel *Panel) (Zone, bool) {
	if panel == nil {
		return 0, false
	}
	for z := Zone(0); z < zoneCount; z++ {
		if h.zones[z].containsPanel(panel) {
			return z, true
		}
	}
	return 0, false
}

func RightRatio

RightRatio sets the size ratio of the right zone (0.0 to 1.0).

Default is 0.2 (20% of available width).

func RightRatio(r float32) HostOption {
	return func(c *hostConfig) { c.rightRatio = clampRatio(r) }
}

func SetActivePanelIndex

SetActivePanelIndex sets the active tab index for the given zone.

Does nothing if the index is out of range.

func (h *Host) SetActivePanelIndex(zone Zone, idx int) {
	if int(zone) >= zoneCount {
		return
	}
	g := &h.zones[zone]
	if idx < 0 || idx >= len(g.panels) {
		return
	}
	g.activeIdx = idx
}

func TopRatio

TopRatio sets the size ratio of the top zone (0.0 to 1.0).

Default is 0.2 (20% of available height).

func TopRatio(r float32) HostOption {
	return func(c *hostConfig) { c.topRatio = clampRatio(r) }
}

func Undock

Undock removes a panel from its current zone.

Returns true if the panel was found and removed.

func (h *Host) Undock(panel *Panel) bool {
	if panel == nil {
		return false
	}
	removed := h.undockFromAll(panel)

	// ADR-028: clear parent on removal.
	if removed {
		if content := panel.Content(); content != nil {
			type parentSetter interface{ SetParent(widget.Widget) }
			if ps, ok := content.(parentSetter); ok {
				ps.SetParent(nil)
			}
		}
	}

	return removed
}

Structs

type Host struct

Host is the root container managing the dock layout.

 

It arranges docked panels into five zones (Left, Right, Top, Bottom, Center)

and renders tab headers for zones with multiple panels.

 

A host is created with [NewHost] using functional options:

 

host := docking.NewHost(

docking.CenterContent(mainEditor),

docking.LeftRatio(0.25),

)

type Host struct {
	widget.WidgetBase
	cfg	hostConfig
	painter	Painter

	// Zone groups, indexed by Zone constant.
	zones	[zoneCount]group

	// Tab interaction state per zone.
	tabStates	[zoneCount][]ZoneTabState
}