package main import ( "fmt" "image" "image/color" "strings" "gioui.org/layout" "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/unit" ) type focusAppearance struct { BorderColor color.NRGBA OutlineColor color.NRGBA OutlineWidth int MinHeight int } func fieldFocusAppearance(metric unit.Metric, focused bool) focusAppearance { appearance := focusAppearance{ BorderColor: color.NRGBA{R: 202, G: 194, B: 180, A: 255}, OutlineColor: color.NRGBA{A: 0}, OutlineWidth: max(1, metric.Dp(unit.Dp(1))), MinHeight: metric.Dp(unit.Dp(44)), } if focused { appearance.BorderColor = accentColor appearance.OutlineColor = color.NRGBA{R: 28, G: 83, B: 63, A: 72} appearance.OutlineWidth = max(2, metric.Dp(unit.Dp(2))) } return appearance } func buttonFocusColors(focused bool) (background color.NRGBA, text color.NRGBA) { background = color.NRGBA{R: 231, G: 239, B: 235, A: 255} text = accentColor if focused { background = color.NRGBA{R: 214, G: 229, B: 221, A: 255} } return background, text } func (u *ui) accessibilityLabel(id focusID) string { switch { case id == focusSearch: return "Search vault" case strings.HasPrefix(string(id), "breadcrumb:"): index := focusIndex(id) crumbs := u.breadcrumbLabels() if index >= 0 && index < len(crumbs) { return fmt.Sprintf("Navigate to %s", crumbs[index]) } case strings.HasPrefix(string(id), "list:"): index := focusIndex(id) if index >= 0 && index < len(u.visible) { return fmt.Sprintf("Select entry %s", u.visible[index].Title) } case strings.HasPrefix(string(id), "detail:"): name := strings.TrimPrefix(string(id), "detail:") return fmt.Sprintf("Edit %s", detailFieldLabel(detailField(name))) } return "" } func drawFocusOutline(gtx layout.Context, appearance focusAppearance, size image.Point) layout.Dimensions { if appearance.OutlineColor.A == 0 || appearance.OutlineWidth <= 0 { return layout.Dimensions{Size: size} } width := appearance.OutlineWidth paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Max: image.Pt(size.X, width)}.Op()) paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Min: image.Pt(0, size.Y-width), Max: image.Pt(size.X, size.Y)}.Op()) paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Max: image.Pt(width, size.Y)}.Op()) paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Min: image.Pt(size.X-width, 0), Max: image.Pt(size.X, size.Y)}.Op()) return layout.Dimensions{Size: size} } func (u *ui) isFocused(id focusID) bool { return u.keyboardFocus == id } func detailFieldLabel(field detailField) string { switch field { case detailFieldID: return "ID" case detailFieldTitle: return "Title" case detailFieldUsername: return "Username" case detailFieldPassword: return "Password" case detailFieldURL: return "URL" case detailFieldPath: return "Path" case detailFieldTags: return "Tags" case detailFieldPasswordProfile: return "Password Profile" case detailFieldNotes: return "Notes" case detailFieldFields: return "Custom Fields" case detailFieldHistoryIndex: return "History Index" default: return strings.ReplaceAll(string(field), "-", " ") } }