From 8b09697e6b4e1f618e11130cc7eb877b16f1b5fd Mon Sep 17 00:00:00 2001 From: Greg Pomerantz Date: Fri, 8 May 2026 15:13:16 -0400 Subject: [PATCH] Add search button to top bar, move cursor info to bottom bar StatusBar (top bar): - Added Search icon (always visible, toggles search bar) - Removed cursor position from top bar (moved to bottom bar) - Fixed icon slots: Cut, Copy, Search, Paste (left to right) - File size between Paste and Conflict icons BottomBar (new element): - Always visible at bottom of editor page (24 DP fixed height) - Left: cursor position (Ln X, Col Y) - Right: word wrap status (On/Off) - Cursor position updated on every cursor movement - Word wrap status persisted to .pad/state.json Search button: - Tap toggles search bar visible/invisible - When active: shows SearchBar element, focuses text field, shows keyboard - When inactive: hides SearchBar, clears query, hides keyboard - Primary search activation method on Android (Ctrl+F still works as secondary) Layout: - Top: StatusBar (filename + action icons) - Middle: SearchBar (when active) + TextField (editor) - Bottom: BottomBar (cursor position + word wrap status) Co-authored-by: Qwen-Coder --- doc/element_model.md | 51 ++++++++++++++++++++++++------- doc/touch.md | 71 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 17 deletions(-) diff --git a/doc/element_model.md b/doc/element_model.md index 1cba1dd..ff1d2de 100644 --- a/doc/element_model.md +++ b/doc/element_model.md @@ -215,10 +215,10 @@ type StatusBar struct { /* region, visible, id — unexported */ Filename string // e.g., "notes.txt" (truncated with ellipsis if too long) FilenameExp bool // true = show full filename (multi-line), false = truncated - Left string // e.g., "Ln 10, Col 5" Right string // e.g., "1024 / 50000 bytes" CutCopy bool // true = show cut icon in left slot Copy bool // true = show copy icon in left slot (next to cut) + Search bool // true = show search icon (toggle search bar) Paste bool // true = show paste icon in right slot ConflictIcon bool // true = show conflict warning icon (rightmost) } @@ -227,19 +227,44 @@ type StatusBar struct { The status bar appears at the top of the editor page. It has a **two-line layout**: - **Line 1**: Filename (truncated with ellipsis if too long). Tapping the ellipsis toggles between truncated and full multi-line view. -- **Line 2**: Action icons (Cut, Copy, Paste) + line/col info + file size + conflict icon. +- **Line 2**: Action icons (Cut, Copy, Search, Paste) + file size + conflict icon. **Fixed icon slots** (24×24 DP each, fixed positions): - **Cut icon**: leftmost action icon - **Copy icon**: second from left (36 DP from Cut icon) -- **Paste icon**: second from right +- **Search icon**: third from left (36 DP from Copy icon) +- **Paste icon**: fourth from left (36 DP from Search icon) - **Conflict icon**: rightmost Icons appear/disappear without reflowing other elements. The StatusBar's `Region.H` is computed dynamically based on whether the filename is truncated (2 lines) or expanded (3+ lines). When a sync conflict is detected for the active file, `ConflictIcon` is set to true. Tapping the icon navigates to the merge resolution page. The icon persists across process death — if a conflict file exists for the active file on restore, the icon appears. -### 3.10 Toast / Notification +### 3.10 Bottom Bar + +```go +type BottomBar struct { + /* region, visible, id — unexported */ + CursorPos string // e.g., "Ln 10, Col 5" + WordWrap bool // true = word wrap is enabled (shown for reference) +} +``` + +The bottom bar appears at the bottom of the editor page. It displays cursor position and editor state information. It is always visible (no icons, just text). + +**Layout**: +``` +┌──────────────────────────────────────────────────────────────┐ +│ Ln 10, Col 5 Word Wrap: On │ +└──────────────────────────────────────────────────────────────┘ +``` + +- **Left**: Cursor position (line number, column number) +- **Right**: Word wrap status (On/Off) + +The BottomBar's `Region.H` is fixed (24 DP). It sits below the editor content. + +### 3.11 Toast / Notification ```go type Toast struct { @@ -318,11 +343,11 @@ Elements are rendered in slice order. Later elements draw on top of earlier ones ``` 1. Background (full screen) -2. Header / Label +2. Status bar (top) 3. Search bar or main content 4. List or text area -5. Overlay elements (cursor, selection highlight, toast) -6. Status bar (bottom) +5. Overlay elements (cursor, selection highlight) +6. Bottom bar ``` ## 7. Theme @@ -356,12 +381,13 @@ Elements that don't specify explicit colors/sizes use theme defaults. The theme []Element{ StatusBar{ Filename: "notes.txt", FilenameExp: false, - Left: "Ln 47, Col 12", Right: "1024 / 50000", - CutCopy: true, Copy: false, Paste: true, ConflictIcon: false, + Right: "1024 / 50000", + CutCopy: true, Copy: false, Search: false, Paste: true, ConflictIcon: false, }, SearchBar{Query: "foo", Match: 1, Total: 3}, // search (when active) TextField{Multiline: true, VisibleLines: [...], ScrollOffset: 420, WordWrap: true}, Cursor{Line: 5, Column: 12, Selection: &Selection{...}}, + BottomBar{CursorPos: "Ln 47, Col 12", WordWrap: true}, } ``` @@ -369,10 +395,13 @@ The search bar is only present when the user has activated search. When visible, The StatusBar contains: - **Filename** on line 1 (truncated with ellipsis if too long) -- **Action icons** (Cut, Copy, Paste) on line 2, fixed positions -- **Line/col info** between Cut/Copy and Paste icons +- **Action icons** (Cut, Copy, Search, Paste) on line 2, fixed positions - **File size** between Paste and Conflict icons +The BottomBar contains: +- **Cursor position** on the left (e.g., "Ln 47, Col 12") +- **Word wrap status** on the right (e.g., "Word Wrap: On") + ### 8.3 Merge Page ``` diff --git a/doc/touch.md b/doc/touch.md index d6a6c51..66408ca 100644 --- a/doc/touch.md +++ b/doc/touch.md @@ -303,17 +303,24 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons ``` ┌──────────────────────────────────────────────────────────────┐ │ filename.txt │ ← Line 1: filename (truncated with ellipsis) -│ [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf] │ ← Line 2: action icons + info +│ [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf] │ ← Line 2: action icons + file size +└──────────────────────────────────────────────────────────────┘ + StatusBar (top bar) +┌──────────────────────────────────────────────────────────────┐ +│ TextField (editor content) │ +└──────────────────────────────────────────────────────────────┘ +┌──────────────────────────────────────────────────────────────┐ +│ Ln 10, Col 5 Word Wrap: On │ ← BottomBar └──────────────────────────────────────────────────────────────┘ ``` **Fixed slot positions** (in Dp, from the edges): - **Cut icon**: leftmost action icon (24×24 DP, fixed position) - **Copy icon**: second from left (24×24 DP, fixed position, 36 DP from Cut icon) -- **Paste icon**: second from right (24×24 DP, fixed position) +- **Search icon**: third from left (24×24 DP, fixed position, 36 DP from Copy icon) +- **Paste icon**: fourth from left (24×24 DP, fixed position, 36 DP from Search icon) - **Conflict icon**: rightmost (24×24 DP, fixed position) - **Filename**: top line, truncated with ellipsis if too long -- **Line/col info**: between Cut/Copy and Paste icons - **File size**: between Paste and Conflict icons **Visibility rules**: @@ -322,6 +329,7 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons |---|---| | **Cut** | `selection_start != selection_end` | | **Copy** | `selection_start != selection_end` | +| **Search** | Always visible (toggle search bar) | | **Paste** | `clipboard != ""` | | **Conflict** | sync conflict detected for active file | @@ -344,6 +352,25 @@ Icons are rendered as `Button` elements with fixed sizes. The StatusBar's `Regio 4. Selection is **not** cleared (text remains in buffer). 5. Logic produces a new frame (Cut/Copy icons still visible, Paste icon appears). +### 5.6.4a Search Button + +The Search button toggles the search bar visible/invisible. + +1. User taps the Search icon. +2. Logic toggles `search_active` state field. +3. If `search_active` is true: + - Show `SearchBar` element below the StatusBar. + - Set focus to the search bar's text field. + - Show the soft keyboard (`key.SoftKeyboardOp(true)`). +4. If `search_active` is false: + - Hide `SearchBar` element. + - Clear search query. + - Remove focus from search bar. + - Hide soft keyboard (`key.SoftKeyboardOp(false)`). +5. Logic produces a new frame. + +The Search button is always visible in the StatusBar (unlike Cut/Copy/Paste which are conditional). It serves as the primary way to activate search on Android (where Ctrl+F may not be available). + ### 5.6.5 Paste Operation 1. User taps the Paste icon. @@ -406,16 +433,48 @@ This field is **not** persisted to disk — it is reset on app restart (same as In the truncated view, the StatusBar has 2 lines: ``` Line 1: filename.txt... -Line 2: [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf] +Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf] ``` In the full view, the StatusBar has 3+ lines (depending on filename length): ``` Line 1: very_long_filename_that_does_not_fit_on_a_single_line.txt -Line 2: [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf] +Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf] ``` -The `Region.H` of the StatusBar is computed dynamically based on the number of lines. +The `Region.H` of the StatusBar is computed dynamically based on the number of lines. The BottomBar is always at the bottom of the screen (24 DP fixed height). + +## 5.8 Bottom Bar + +The Bottom Bar appears at the bottom of the editor page. It displays cursor position and editor state information. It is always visible (no icons, just text). + +### 5.8.1 Layout + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Ln 10, Col 5 Word Wrap: On │ +└──────────────────────────────────────────────────────────────┘ +``` + +- **Left**: Cursor position (e.g., "Ln 10, Col 5") +- **Right**: Word wrap status (e.g., "Word Wrap: On") + +The BottomBar's `Region.H` is fixed at 24 DP. It sits below the editor content. + +### 5.8.2 Cursor Position + +The cursor position is computed from the current byte offset: +1. Logic converts byte offset to (line, column) using the **Line Index**. +2. The `CursorPos` field is set to `"Ln {line}, Col {column}"`. +3. The field is updated on every cursor movement (tap, arrow keys, backspace, etc.). + +### 5.8.3 Word Wrap Status + +The word wrap status is a simple boolean field (`word_wrap_enabled`): +- `true` → "Word Wrap: On" +- `false` → "Word Wrap: Off" + +This field is persisted to `.pad/state.json` and restored on app start. Toggling word wrap is done via a settings screen (not yet implemented). ## 6. Scroll Momentum