package ui import ( "gioui.org/layout" "gioui.org/unit" "gioui.org/widget" "gioui.org/widget/material" "git.wxccs.org/iceking2nd/winauth-go/internal/i18n" ) // rowAction is what the per-row ⋯ popup returns to the caller. type rowAction int const ( rowActionNone rowAction = iota rowActionRename rowActionDelete rowActionMoveUp rowActionMoveDown rowActionChangeIcon ) // rowActionMenu is the small popup opened by the ⋯ button on each entry // row. It carries the target entry index so the caller knows which row // the chosen action applies to. moveUp/moveDown are disabled (rendered // but inert) when the index is at a boundary. type rowActionMenu struct { idx int canMoveUp bool canMoveDown bool renameBtn widget.Clickable deleteBtn widget.Clickable moveUpBtn widget.Clickable moveDownBtn widget.Clickable changeIconBtn widget.Clickable cancelBtn widget.Clickable } func newRowActionMenu(idx, total int) *rowActionMenu { return &rowActionMenu{ idx: idx, canMoveUp: idx > 0, canMoveDown: idx < total-1, } } // Pick reports the user's choice and whether the menu should close. func (m *rowActionMenu) Pick(gtx layout.Context) (rowAction, bool) { switch { case m.renameBtn.Clicked(gtx): return rowActionRename, true case m.deleteBtn.Clicked(gtx): return rowActionDelete, true case m.moveUpBtn.Clicked(gtx): if !m.canMoveUp { return rowActionNone, false } return rowActionMoveUp, true case m.moveDownBtn.Clicked(gtx): if !m.canMoveDown { return rowActionNone, false } return rowActionMoveDown, true case m.changeIconBtn.Clicked(gtx): return rowActionChangeIcon, true case m.cancelBtn.Clicked(gtx): return rowActionNone, true } return rowActionNone, false } func (m *rowActionMenu) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions { fillBackground(gtx, activePalette.ScrimBg) row := func(btn *widget.Clickable, label string, enabled bool) layout.FlexChild { return layout.Rigid(func(gtx layout.Context) layout.Dimensions { return layout.Inset{Top: unit.Dp(4), Bottom: unit.Dp(4)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions { gtx.Constraints.Min.X = gtx.Constraints.Max.X b := material.Button(th, btn, label) if !enabled { // Visually dim the disabled state; Pick also // refuses to dispatch the action so clicks // are inert beyond the colour change. b.Background = activePalette.RingBg b.Color = activePalette.MutedFg } return b.Layout(gtx) }) }) } return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { gtx.Constraints.Max.X = gtx.Dp(260) return widget.Border{ Color: activePalette.DialogBorder, CornerRadius: unit.Dp(4), Width: unit.Dp(1), }.Layout(gtx, func(gtx layout.Context) layout.Dimensions { fillBackground(gtx, activePalette.DialogBg) return layout.UniformInset(unit.Dp(16)).Layout(gtx, func(gtx layout.Context) layout.Dimensions { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(material.H6(th, i18n.T("dialog_row_actions_title")).Layout), layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout), row(&m.renameBtn, i18n.T("action_rename"), true), row(&m.deleteBtn, i18n.T("action_delete"), true), row(&m.changeIconBtn, i18n.T("action_change_icon"), true), row(&m.moveUpBtn, i18n.T("action_move_up"), m.canMoveUp), row(&m.moveDownBtn, i18n.T("action_move_down"), m.canMoveDown), layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceStart}.Layout(gtx, layout.Rigid(material.Button(th, &m.cancelBtn, i18n.T("btn_cancel")).Layout), ) }), ) }) }) }) }