theme/material3/menu.go

Functions Structs

Functions

func PaintMenu

PaintMenu renders a popup menu panel with M3 surface and elevation styling.

func (p MenuPainter) PaintMenu(canvas widget.Canvas, st *menu.MenuPaintState) {
	if st.Bounds.IsEmpty() {
		return
	}

	colors := p.effectiveMenuColors(st.ColorScheme)

	// Elevation shadow.
	shadowRect := geometry.Rect{
		Min:	geometry.Pt(st.Bounds.Min.X+m3MenuShadowOffset, st.Bounds.Min.Y+m3MenuShadowOffset),
		Max:	geometry.Pt(st.Bounds.Max.X+m3MenuShadowOffset, st.Bounds.Max.Y+m3MenuShadowOffset),
	}
	canvas.DrawRoundRect(shadowRect, m3MenuShadowColor, m3MenuRadius)

	// Menu surface.
	canvas.DrawRoundRect(st.Bounds, colors.MenuBackground, m3MenuRadius)
	canvas.StrokeRoundRect(st.Bounds, colors.MenuBorder, m3MenuRadius, m3MenuBorderWidth)

	// Clip to menu bounds.
	canvas.PushClip(st.Bounds)
	defer canvas.PopClip()

	// Draw items.
	y := st.Bounds.Min.Y + m3MenuPaddingV
	for i, item := range st.Items {
		if item.IsSeparator() {
			m3PaintMenuSeparator(canvas, st.Bounds.Min.X, y, st.Bounds.Width(), st.SeparatorHeight, colors.SeparatorColor)
			y += st.SeparatorHeight
			continue
		}

		itemRect := geometry.Rect{
			Min:	geometry.Pt(st.Bounds.Min.X, y),
			Max:	geometry.Pt(st.Bounds.Max.X, y+st.ItemHeight),
		}

		// Highlight.
		if i == st.HighlightedIndex && !item.Disabled {
			canvas.DrawRoundRect(
				geometry.NewRect(itemRect.Min.X+m3MenuItemInset, itemRect.Min.Y, itemRect.Width()-m3MenuItemInset*2, st.ItemHeight),
				colors.ItemHover, m3MenuItemRadius,
			)
		}

		// Label.
		textColor := colors.ItemText
		if item.Disabled {
			textColor = colors.ItemDisabledText
		}
		labelRect := geometry.Rect{
			Min:	geometry.Pt(itemRect.Min.X+m3MenuItemPaddingH, itemRect.Min.Y),
			Max:	geometry.Pt(itemRect.Max.X-m3MenuShortcutWidth-m3MenuItemPaddingH, itemRect.Max.Y),
		}
		canvas.DrawText(item.Label, labelRect, m3MenuFontSize, textColor, false, widget.TextAlignLeft)

		// Shortcut text or submenu arrow.
		rightRect := geometry.Rect{
			Min:	geometry.Pt(itemRect.Max.X-m3MenuShortcutWidth, itemRect.Min.Y),
			Max:	geometry.Pt(itemRect.Max.X-m3MenuItemPaddingH, itemRect.Max.Y),
		}
		if item.HasChildren() {
			arrowColor := colors.SubMenuArrow
			if item.Disabled {
				arrowColor = colors.ItemDisabledText
			}
			canvas.DrawText(m3MenuRightArrow, rightRect, m3MenuFontSize, arrowColor, false, widget.TextAlignRight)
		} else if item.Shortcut != "" {
			shortcutColor := colors.ShortcutText
			if item.Disabled {
				shortcutColor = colors.ItemDisabledText
			}
			canvas.DrawText(item.Shortcut, rightRect, m3MenuShortcutFontSize, shortcutColor, false, widget.TextAlignRight)
		}

		y += st.ItemHeight
	}
}

func PaintMenuBar

PaintMenuBar renders a menu bar with M3 surface and elevation styling.

func (p MenuPainter) PaintMenuBar(canvas widget.Canvas, st *menu.MenuBarPaintState) {
	if st.Bounds.IsEmpty() {
		return
	}

	colors := p.effectiveBarColors(st.ColorScheme)

	// Bar background.
	canvas.DrawRect(st.Bounds, colors.BarBackground)

	// Bottom border.
	borderRect := geometry.Rect{
		Min:	geometry.Pt(st.Bounds.Min.X, st.Bounds.Max.Y-m3MenuBorderWidth),
		Max:	st.Bounds.Max,
	}
	canvas.DrawRect(borderRect, colors.MenuBorder)

	// Draw each top-level menu label.
	for i, m := range st.Menus {
		if i >= len(st.MenuRects) {
			break
		}
		r := st.MenuRects[i]

		// Highlight background.
		switch i {
		case st.OpenIndex:
			canvas.DrawRoundRect(r, colors.ItemHover, m3MenuBarItemRadius)
		case st.HoveredIndex:
			canvas.DrawRoundRect(r, colors.BarHover, m3MenuBarItemRadius)
		}

		// Label text.
		textColor := colors.BarText
		if i == st.OpenIndex {
			textColor = colors.BarActiveText
		}
		textBounds := geometry.Rect{
			Min:	geometry.Pt(r.Min.X+m3MenuBarPaddingH, r.Min.Y),
			Max:	geometry.Pt(r.Max.X-m3MenuBarPaddingH, r.Max.Y),
		}
		canvas.DrawText(m.Label, textBounds, m3MenuFontSize, textColor, false, widget.TextAlignCenter)
	}
}

Structs

type MenuPainter struct

MenuPainter renders menus and menu bars using Material 3 design tokens.

It maps M3 color roles to menu elements: surface for containers, elevation

shadow for depth, on-surface for text, and primary for highlight states.

 

If Theme is nil, MenuPainter falls back to the default M3 purple palette.

type MenuPainter struct {
	Theme *Theme	// nil uses default M3 purple fallback
}