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.
This commit is contained in:
Grok 2026-06-06 15:59:22 +01:00
parent 0812bc162f
commit b142d8305c
2 changed files with 34 additions and 6 deletions

View File

@ -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. - Operators (+ - * / =): accent color 63 for quick recognition.
- Clears (C, AC): red-tinted bg 52 + fg 203 (warning/danger). - Clears (C, AC): red-tinted bg 52 + fg 203 (warning/danger).
- MOD: highlighted (214 orange). - 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). - 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. - Keys use Height(2) for chunkier, more button-like presence.
- Spacing (" " gaps) between keys. - Spacing (" " gaps) between keys.
The keys sit directly on the main card background (no faceplate container). 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 7 8 9 / MOD
4 5 6 * C 4 5 6 * C
1 2 3 - AC 1 2 3 - AC
0 . +/- + = 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. 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.

View File

@ -234,6 +234,7 @@ func (a *App) View() string {
opKey := keyStyle.Copy().Foreground(lipgloss.Color("63")).Background(lipgloss.Color("235")) opKey := keyStyle.Copy().Foreground(lipgloss.Color("63")).Background(lipgloss.Color("235"))
clearKey := keyStyle.Copy().Foreground(lipgloss.Color("203")).Background(lipgloss.Color("52")) clearKey := keyStyle.Copy().Foreground(lipgloss.Color("203")).Background(lipgloss.Color("52"))
modKey := keyStyle.Copy().Foreground(lipgloss.Color("214")) // orange-ish for MOD 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 { makeKey := func(label string) string {
var st lipgloss.Style 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")) 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("=")) 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). var rawGrid string
rawGrid := lipgloss.JoinVertical(lipgloss.Left, row1, row2, row3, row4) 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. // Center the key grid directly under the display.
// No enclosing container — just the individually styled keys. // 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(). keypad := lipgloss.NewStyle().
Width(dispW). Width(dispW).
Align(lipgloss.Center). Align(lipgloss.Center).