Align header action cluster with layout.E

This commit is contained in:
Joe Julian
2026-04-10 15:04:41 -07:00
parent 2f1cd7876c
commit 0e9fd478e5
4 changed files with 101 additions and 82 deletions
+54 -13
View File
@@ -9,6 +9,7 @@ import (
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
headerview "git.julianfamily.org/keepassgo/internal/appui/header"
headerlayout "git.julianfamily.org/keepassgo/internal/appui/header/layout"
)
@@ -25,10 +26,10 @@ func (u *ui) header(gtx layout.Context) layout.Dimensions {
}
return card(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Alignment: layout.Middle}.Layout(gtx,
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.brandMark(gtx, 196, 56)
}),
layout.Rigid(u.headerActions),
layout.Flexed(1, u.headerActions),
)
})
}
@@ -39,7 +40,7 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
}
spacing := gtx.Dp(unit.Dp(8))
metrics := headerlayout.ActionMetrics{Spacing: spacing}
row := func(gtx layout.Context) layout.Dimensions {
actionCluster := func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
metrics.SyncDims = u.syncButtonGroup(gtx)
@@ -60,18 +61,16 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
}
rowOps := op.Record(gtx.Ops)
metrics.RowDims = row(gtx)
metrics.RowDims = actionCluster(gtx)
rowCall := rowOps.Stop()
if u.usesCompactViewport() {
metrics.RowOriginX = max(0, gtx.Constraints.Max.X-metrics.RowDims.Size.X)
}
metrics.RowOriginX = max(0, gtx.Constraints.Max.X-metrics.RowDims.Size.X)
surface := headerlayout.DropdownSurface{ContainerWidth: gtx.Constraints.Max.X, LeftInset: 0, TopInset: 0}
rowStack := op.Offset(image.Pt(metrics.RowOriginX, 0)).Push(gtx.Ops)
rowCall.Add(gtx.Ops)
rowStack.Pop()
rowDims := layout.E.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
rowCall.Add(gtx.Ops)
return metrics.RowDims
})
if u.usesCompactViewport() {
if u.syncMenuOpen {
@@ -82,7 +81,7 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
u.phoneMainMenuVisible = true
u.phoneMainMenuAnchor = metrics.MainAnchor().Point()
}
return layout.Dimensions{Size: image.Pt(gtx.Constraints.Max.X, metrics.RowDims.Size.Y)}
return layout.Dimensions{Size: image.Pt(gtx.Constraints.Max.X, rowDims.Size.Y)}
}
if u.syncMenuOpen {
@@ -92,7 +91,7 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
surface.Draw(gtx, metrics.MainAnchor(), u.mainMenu)
}
return layout.Dimensions{Size: image.Pt(metrics.RowDims.Size.X, metrics.RowDims.Size.Y)}
return rowDims
}
func (u *ui) topRightActionOrder() []string {
@@ -174,3 +173,45 @@ func (u *ui) brandImage(gtx layout.Context, src paint.ImageOp, widthDP, heightDP
gtx.Constraints.Max = image.Pt(width, height)
return img.Layout(gtx)
}
func (u *ui) mainMenu(gtx layout.Context) layout.Dimensions {
rows := []layout.Widget{
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showEntries, "Entries")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showRecycle, "Recycle Bin")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showAPITokens, "API Tokens")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showAPIAudit, "API Audit")
},
func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showAbout, "About") },
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Settings")
},
}
return headerview.MainMenu(gtx, u.theme, rows, compactCard)
}
func (u *ui) mainMenuButtonGroup(gtx layout.Context) layout.Dimensions {
icon := u.menuIcon
if icon == nil {
icon = u.settingsIcon
}
return headerview.MainMenuButtonGroup(gtx, u.theme, &u.toggleMainMenu, icon, u.mainMenuOpen, selectedColor, accentColor)
}
func intrinsicCompactCard(gtx layout.Context, w layout.Widget) layout.Dimensions {
return headerlayout.IntrinsicCompactCard(gtx, w, compactCard)
}
func menuActionWidth(gtx layout.Context, rows []layout.Widget) int {
return headerlayout.MenuActionWidth(gtx, rows)
}
func rightAlignedMenuAction(gtx layout.Context, width int, child layout.Widget) layout.Dimensions {
return headerlayout.RightAlignedAction(gtx, width, child)
}
@@ -1,4 +1,4 @@
package appui
package layout
import (
"image"
@@ -8,7 +8,7 @@ import (
"gioui.org/unit"
)
func intrinsicCompactCard(gtx layout.Context, w layout.Widget) layout.Dimensions {
func IntrinsicCompactCard(gtx layout.Context, w layout.Widget, card func(layout.Context, layout.Widget) layout.Dimensions) layout.Dimensions {
measureGTX := gtx
measureGTX.Constraints.Min = image.Point{}
measureGTX.Constraints.Max.X = gtx.Constraints.Max.X
@@ -24,10 +24,10 @@ func intrinsicCompactCard(gtx layout.Context, w layout.Widget) layout.Dimensions
gtx.Constraints.Min.X = width
gtx.Constraints.Max.X = width
}
return compactCard(gtx, w)
return card(gtx, w)
}
func menuActionWidth(gtx layout.Context, rows []layout.Widget) int {
func MenuActionWidth(gtx layout.Context, rows []layout.Widget) int {
width := 0
for _, row := range rows {
measureGTX := gtx
@@ -42,7 +42,7 @@ func menuActionWidth(gtx layout.Context, rows []layout.Widget) int {
return width
}
func rightAlignedMenuAction(gtx layout.Context, width int, child layout.Widget) layout.Dimensions {
func RightAlignedAction(gtx layout.Context, width int, child layout.Widget) layout.Dimensions {
if width <= 0 {
return child(gtx)
}
+42
View File
@@ -0,0 +1,42 @@
package header
import (
"image/color"
"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
headerlayout "git.julianfamily.org/keepassgo/internal/appui/header/layout"
)
func MainMenu(gtx layout.Context, theme *material.Theme, rows []layout.Widget, card func(layout.Context, layout.Widget) layout.Dimensions) layout.Dimensions {
rowWidth := headerlayout.MenuActionWidth(gtx, rows)
return headerlayout.IntrinsicCompactCard(gtx, func(gtx layout.Context) layout.Dimensions {
children := make([]layout.FlexChild, 0, (len(rows)*2)-1)
for i, row := range rows {
if i > 0 {
children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout))
}
current := row
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return headerlayout.RightAlignedAction(gtx, rowWidth, current)
}))
}
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...)
}, card)
}
func MainMenuButtonGroup(gtx layout.Context, theme *material.Theme, click *widget.Clickable, icon *widget.Icon, open bool, selectedColor, accentColor color.NRGBA) layout.Dimensions {
btn := material.IconButton(theme, click, icon, "Menu")
if open {
btn.Background = accentColor
btn.Color = color.NRGBA{R: 255, G: 252, B: 247, A: 255}
} else {
btn.Background = selectedColor
btn.Color = accentColor
}
btn.Size = unit.Dp(18)
btn.Inset = layout.UniformInset(unit.Dp(8))
return btn.Layout(gtx)
}
-64
View File
@@ -1,64 +0,0 @@
package appui
import (
"image/color"
"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget/material"
)
func (u *ui) mainMenu(gtx layout.Context) layout.Dimensions {
rows := []layout.Widget{
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showEntries, "Entries")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showRecycle, "Recycle Bin")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showAPITokens, "API Tokens")
},
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.showAPIAudit, "API Audit")
},
func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showAbout, "About") },
func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Settings")
},
}
rowWidth := menuActionWidth(gtx, rows)
return intrinsicCompactCard(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[0]) }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[1]) }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[2]) }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[3]) }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[4]) }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, rowWidth, rows[5]) }),
)
})
}
func (u *ui) mainMenuButtonGroup(gtx layout.Context) layout.Dimensions {
icon := u.menuIcon
if icon == nil {
icon = u.settingsIcon
}
btn := material.IconButton(u.theme, &u.toggleMainMenu, icon, "Menu")
if u.mainMenuOpen {
btn.Background = accentColor
btn.Color = color.NRGBA{R: 255, G: 252, B: 247, A: 255}
} else {
btn.Background = selectedColor
btn.Color = accentColor
}
btn.Size = unit.Dp(18)
btn.Inset = layout.UniformInset(unit.Dp(8))
return btn.Layout(gtx)
}