132 lines
3.6 KiB
Go
132 lines
3.6 KiB
Go
package layout
|
|
|
|
import (
|
|
"image"
|
|
|
|
"gioui.org/layout"
|
|
"gioui.org/op"
|
|
"gioui.org/unit"
|
|
)
|
|
|
|
func AnchoredMenuX(triggerWidth, menuWidth int) int {
|
|
return triggerWidth - menuWidth
|
|
}
|
|
|
|
func AnchoredMenuOriginX(containerWidth, rowOriginX, triggerRightX, menuWidth int) int {
|
|
x := rowOriginX + triggerRightX - menuWidth
|
|
if x < 0 {
|
|
return 0
|
|
}
|
|
if x+menuWidth > containerWidth {
|
|
return max(0, containerWidth-menuWidth)
|
|
}
|
|
return x
|
|
}
|
|
|
|
type DropdownAnchor struct {
|
|
TriggerRightX int
|
|
TriggerBottomY int
|
|
}
|
|
|
|
func (a DropdownAnchor) Point() image.Point {
|
|
return image.Pt(a.TriggerRightX, a.TriggerBottomY)
|
|
}
|
|
|
|
type DropdownSurface struct {
|
|
ContainerWidth int
|
|
LeftInset int
|
|
TopInset int
|
|
}
|
|
|
|
type DropdownPlacement struct {
|
|
Anchor DropdownAnchor
|
|
Origin image.Point
|
|
Size image.Point
|
|
}
|
|
|
|
func (s DropdownSurface) MenuConstraints(gtx layout.Context) layout.Context {
|
|
menuGTX := gtx
|
|
menuGTX.Constraints.Min = image.Point{}
|
|
menuGTX.Constraints.Max.X = max(0, s.ContainerWidth)
|
|
return menuGTX
|
|
}
|
|
|
|
func (s DropdownSurface) Origin(anchor DropdownAnchor, menuWidth int) image.Point {
|
|
x := s.LeftInset + AnchoredMenuOriginX(s.ContainerWidth, 0, anchor.TriggerRightX, menuWidth)
|
|
y := s.TopInset + anchor.TriggerBottomY
|
|
return image.Pt(x, y)
|
|
}
|
|
|
|
func (s DropdownSurface) Place(gtx layout.Context, anchor DropdownAnchor, menu layout.Widget) (DropdownPlacement, op.CallOp) {
|
|
menuGTX := s.MenuConstraints(gtx)
|
|
menuOps := op.Record(gtx.Ops)
|
|
menuDims := layout.Inset{Top: unit.Dp(6)}.Layout(menuGTX, menu)
|
|
menuCall := menuOps.Stop()
|
|
menuOrigin := s.Origin(anchor, menuDims.Size.X)
|
|
return DropdownPlacement{
|
|
Anchor: anchor,
|
|
Origin: menuOrigin,
|
|
Size: menuDims.Size,
|
|
}, menuCall
|
|
}
|
|
|
|
func (s DropdownSurface) Draw(gtx layout.Context, anchor DropdownAnchor, menu layout.Widget) layout.Dimensions {
|
|
placement, menuCall := s.Place(gtx, anchor, menu)
|
|
stack := op.Offset(placement.Origin).Push(gtx.Ops)
|
|
menuCall.Add(gtx.Ops)
|
|
stack.Pop()
|
|
return layout.Dimensions{Size: gtx.Constraints.Max}
|
|
}
|
|
|
|
type ActionMetrics struct {
|
|
RowOriginX int
|
|
Spacing int
|
|
SyncInnerSpacing int
|
|
RowDims layout.Dimensions
|
|
SyncDims layout.Dimensions
|
|
SyncPrimaryDims layout.Dimensions
|
|
SyncToggleDims layout.Dimensions
|
|
LockDims layout.Dimensions
|
|
MainDims layout.Dimensions
|
|
}
|
|
|
|
func (m ActionMetrics) SyncAnchor() DropdownAnchor {
|
|
return DropdownAnchor{
|
|
TriggerRightX: m.RowOriginX + m.SyncDims.Size.X,
|
|
TriggerBottomY: m.RowDims.Size.Y,
|
|
}
|
|
}
|
|
|
|
func (m ActionMetrics) MainAnchor() DropdownAnchor {
|
|
triggerRightX := m.SyncDims.Size.X + m.Spacing + m.LockDims.Size.X + m.Spacing + m.MainDims.Size.X
|
|
return DropdownAnchor{
|
|
TriggerRightX: m.RowOriginX + triggerRightX,
|
|
TriggerBottomY: m.RowDims.Size.Y,
|
|
}
|
|
}
|
|
|
|
type ActionBounds struct {
|
|
SyncPrimary image.Rectangle
|
|
SyncToggle image.Rectangle
|
|
Lock image.Rectangle
|
|
MainMenu image.Rectangle
|
|
}
|
|
|
|
func (m ActionMetrics) Bounds() ActionBounds {
|
|
top := 0
|
|
syncLeft := m.RowOriginX
|
|
syncPrimary := image.Rect(syncLeft, top, syncLeft+m.SyncPrimaryDims.Size.X, top+m.SyncPrimaryDims.Size.Y)
|
|
syncToggleLeft := syncPrimary.Max.X + m.SyncInnerSpacing
|
|
syncToggle := image.Rect(syncToggleLeft, top, syncToggleLeft+m.SyncToggleDims.Size.X, top+m.SyncToggleDims.Size.Y)
|
|
lockLeft := syncLeft + m.SyncDims.Size.X + m.Spacing
|
|
lock := image.Rect(lockLeft, top, lockLeft+m.LockDims.Size.X, top+m.LockDims.Size.Y)
|
|
mainLeft := lock.Max.X + m.Spacing
|
|
mainMenu := image.Rect(mainLeft, top, mainLeft+m.MainDims.Size.X, top+m.MainDims.Size.Y)
|
|
return ActionBounds{
|
|
SyncPrimary: syncPrimary,
|
|
SyncToggle: syncToggle,
|
|
Lock: lock,
|
|
MainMenu: mainMenu,
|
|
}
|
|
}
|