From b142d8305c44e477ddcb8fab211cb43a2b639b0a Mon Sep 17 00:00:00 2001 From: Grok Date: Sat, 6 Jun 2026 15:59:22 +0100 Subject: [PATCH] ui: dynamic A-F buttons in keypad that only appear in HEX mode - A-F (hex digits) now render as additional top row in the keypad *only* when CurrentBase() == HEX (i.e., after Tab). - Used dedicated hexBtn + hexKey style (orange accent) for the A-F row to avoid label conflict with the 'C' clear button. - Pressed flash works for A-F via existing pressedKey mechanism (set in the HEX entry keyboard handler). - The numeric 4-row grid remains unchanged in other modes. - Updated UI_DESIGN.md layout sketch and description to document the dynamic behavior. - Matches the galculator-inspired 'only when in hex mode' and keeps the keypad clean otherwise. - Build verified. --- docs/UI_DESIGN.md | 17 +++++++++++++---- internal/ui/ui.go | 23 +++++++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/docs/UI_DESIGN.md b/docs/UI_DESIGN.md index b840532..72100bd 100644 --- a/docs/UI_DESIGN.md +++ b/docs/UI_DESIGN.md @@ -33,24 +33,33 @@ The keypad is decorated to evoke a physical, tactile calculator using only the k - Operators (+ - * / =): accent color 63 for quick recognition. - Clears (C, AC): red-tinted bg 52 + fg 203 (warning/danger). - MOD: highlighted (214 orange). - - BASE: prominent border color 63 + bold (stands out as the special display function). + - (A-F appear only in HEX mode — see below) - Pressed state: the key inverts to the bright flashStyle (white fg on 63 bg, bold) for ~140ms on every action. This provides immediate "tactile click" visual feedback (modeled directly on gostations volume/skip/stop flashes). - Keys use Height(2) for chunkier, more button-like presence. - Spacing (" " gaps) between keys. The keys sit directly on the main card background (no faceplate container). -Layout sketch (subject to refinement; 4-5 columns): +Layout sketch (subject to refinement; dynamic based on mode): +Normal mode (DEC/BIN/OCT): ``` 7 8 9 / MOD 4 5 6 * C 1 2 3 - AC 0 . +/- + = - BASE ``` -The BASE action (cycle display format) is available via the `Tab` key (documented in the hint row). There is no on-screen BASE button in the keypad grid. This keeps the button layout regular and avoids awkward single-button rows, while still making the feature easily discoverable via the persistent hint. +HEX mode (A-F row appears only after Tab into HEX): +``` + A B C D E F + 7 8 9 / MOD + 4 5 6 * C + 1 2 3 - AC + 0 . +/- + = +``` + +The BASE action (cycle display format) is available via the `Tab` key (documented in the hint row). There is no on-screen BASE button. A-F buttons appear dynamically only when the base indicator shows HEX. This keeps the button layout regular while making hex entry discoverable. All important actions have direct keys (digits, operators, =/Enter, Backspace, Tab for BASE, c/C, etc.). The on-screen buttons are primarily visual + mouse targets. diff --git a/internal/ui/ui.go b/internal/ui/ui.go index 08586e7..6f94c5c 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -234,6 +234,7 @@ func (a *App) View() string { opKey := keyStyle.Copy().Foreground(lipgloss.Color("63")).Background(lipgloss.Color("235")) clearKey := keyStyle.Copy().Foreground(lipgloss.Color("203")).Background(lipgloss.Color("52")) modKey := keyStyle.Copy().Foreground(lipgloss.Color("214")) // orange-ish for MOD + hexKey := keyStyle.Copy().Foreground(lipgloss.Color("214")).Background(lipgloss.Color("235")) // for A-F, only shown in HEX mode makeKey := func(label string) string { var st lipgloss.Style @@ -263,11 +264,29 @@ func (a *App) View() string { row3 := lipgloss.JoinHorizontal(lipgloss.Top, makeKey("1"), spacer, makeKey("2"), spacer, makeKey("3"), spacer, makeKey("-"), spacer, makeKey("AC")) row4 := lipgloss.JoinHorizontal(lipgloss.Top, makeKey("0"), spacer, makeKey("."), spacer, makeKey("+/-"), spacer, makeKey("+"), spacer, makeKey("=")) - // Compact 4-row keypad grid (BASE action is Tab-only; see hint). - rawGrid := lipgloss.JoinVertical(lipgloss.Left, row1, row2, row3, row4) + var rawGrid string + if a.engine.CurrentBase() == calc.BaseHEX { + // HEX mode only: A-F row appears at the top of the keypad (only after Tab into HEX). + // Use dedicated hexBtn to force hexKey style (avoids label conflict with "C" clear button). + hexBtn := func(label string) string { + st := hexKey + if a.pressedKey == label { + st = pressedStyle + } + return st.Render(label) + } + hexRow := lipgloss.JoinHorizontal(lipgloss.Top, + hexBtn("A"), spacer, hexBtn("B"), spacer, hexBtn("C"), spacer, hexBtn("D"), spacer, hexBtn("E"), spacer, hexBtn("F"), + ) + rawGrid = lipgloss.JoinVertical(lipgloss.Left, hexRow, row1, row2, row3, row4) + } else { + // Normal mode: standard 4-row grid (no A-F) + rawGrid = lipgloss.JoinVertical(lipgloss.Left, row1, row2, row3, row4) + } // Center the key grid directly under the display. // No enclosing container — just the individually styled keys. + // When in HEX the A-F row appears at the top of the keypad. keypad := lipgloss.NewStyle(). Width(dispW). Align(lipgloss.Center).