Re-arrange top bar icons, move byte position to bottom bar
StatusBar (top bar):
- Icons re-arranged: [Cut] [Copy] [Paste] on left, [Conf] [Search] on right
- Removed Right/BytePosition field (moved to BottomBar)
BottomBar:
- Added BytePos field (e.g., "1024 / 50000 bytes")
- Word wrap is now a button (tap to toggle On/Off)
- Layout: CursorPos (left) | BytePos (center) | WordWrap button (right)
Element changes:
- StatusBar: removed Right field, added Search field
- BottomBar: added BytePos field, WordWrap is now a button
Interaction:
- Word wrap tap sends InputEvent{ElementID: "word_wrap"} to Logic
- Logic toggles word_wrap_enabled state field
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
8b09697e6b
commit
9f36806a4f
|
|
@ -215,26 +215,25 @@ type StatusBar struct {
|
||||||
/* region, visible, id — unexported */
|
/* region, visible, id — unexported */
|
||||||
Filename string // e.g., "notes.txt" (truncated with ellipsis if too long)
|
Filename string // e.g., "notes.txt" (truncated with ellipsis if too long)
|
||||||
FilenameExp bool // true = show full filename (multi-line), false = truncated
|
FilenameExp bool // true = show full filename (multi-line), false = truncated
|
||||||
Right string // e.g., "1024 / 50000 bytes"
|
|
||||||
CutCopy bool // true = show cut icon in left slot
|
CutCopy bool // true = show cut icon in left slot
|
||||||
Copy bool // true = show copy icon in left slot (next to cut)
|
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 left slot (next to copy)
|
||||||
Paste bool // true = show paste icon in right slot
|
ConflictIcon bool // true = show conflict warning icon (right side)
|
||||||
ConflictIcon bool // true = show conflict warning icon (rightmost)
|
Search bool // true = show search icon (right side, next to conflict)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The status bar appears at the top of the editor page. It has a **two-line layout**:
|
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 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, Search, Paste) + file size + conflict icon.
|
- **Line 2**: Action icons (Cut, Copy, Paste) on the left + conflict icon + search icon on the right.
|
||||||
|
|
||||||
**Fixed icon slots** (24×24 DP each, fixed positions):
|
**Fixed icon slots** (24×24 DP each, fixed positions):
|
||||||
- **Cut icon**: leftmost action icon
|
- **Cut icon**: leftmost action icon
|
||||||
- **Copy icon**: second from left (36 DP from Cut icon)
|
- **Copy icon**: second from left (36 DP from Cut icon)
|
||||||
- **Search icon**: third from left (36 DP from Copy icon)
|
- **Paste icon**: third from left (36 DP from Copy icon)
|
||||||
- **Paste icon**: fourth from left (36 DP from Search icon)
|
- **Conflict icon**: right side (36 DP from Search icon)
|
||||||
- **Conflict icon**: rightmost
|
- **Search icon**: rightmost (36 DP from Conflict icon)
|
||||||
|
|
||||||
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).
|
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).
|
||||||
|
|
||||||
|
|
@ -246,21 +245,23 @@ When a sync conflict is detected for the active file, `ConflictIcon` is set to t
|
||||||
type BottomBar struct {
|
type BottomBar struct {
|
||||||
/* region, visible, id — unexported */
|
/* region, visible, id — unexported */
|
||||||
CursorPos string // e.g., "Ln 10, Col 5"
|
CursorPos string // e.g., "Ln 10, Col 5"
|
||||||
WordWrap bool // true = word wrap is enabled (shown for reference)
|
BytePos string // e.g., "1024 / 50000 bytes"
|
||||||
|
WordWrap bool // true = word wrap is enabled (button: tap to toggle)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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).
|
The bottom bar appears at the bottom of the editor page. It displays cursor position, byte position, and word wrap status. It is always visible.
|
||||||
|
|
||||||
**Layout**:
|
**Layout**:
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ Ln 10, Col 5 Word Wrap: On │
|
│ Ln 10, Col 5 1024 / 50000 [Word Wrap: On] │
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Left**: Cursor position (line number, column number)
|
- **Left**: Cursor position (line number, column number)
|
||||||
- **Right**: Word wrap status (On/Off)
|
- **Center**: Byte position (current byte / total file bytes)
|
||||||
|
- **Right**: Word wrap button (tap to toggle On/Off)
|
||||||
|
|
||||||
The BottomBar's `Region.H` is fixed (24 DP). It sits below the editor content.
|
The BottomBar's `Region.H` is fixed (24 DP). It sits below the editor content.
|
||||||
|
|
||||||
|
|
@ -381,13 +382,12 @@ Elements that don't specify explicit colors/sizes use theme defaults. The theme
|
||||||
[]Element{
|
[]Element{
|
||||||
StatusBar{
|
StatusBar{
|
||||||
Filename: "notes.txt", FilenameExp: false,
|
Filename: "notes.txt", FilenameExp: false,
|
||||||
Right: "1024 / 50000",
|
CutCopy: true, Copy: false, Paste: true, ConflictIcon: false, Search: false,
|
||||||
CutCopy: true, Copy: false, Search: false, Paste: true, ConflictIcon: false,
|
|
||||||
},
|
},
|
||||||
SearchBar{Query: "foo", Match: 1, Total: 3}, // search (when active)
|
SearchBar{Query: "foo", Match: 1, Total: 3}, // search (when active)
|
||||||
TextField{Multiline: true, VisibleLines: [...], ScrollOffset: 420, WordWrap: true},
|
TextField{Multiline: true, VisibleLines: [...], ScrollOffset: 420, WordWrap: true},
|
||||||
Cursor{Line: 5, Column: 12, Selection: &Selection{...}},
|
Cursor{Line: 5, Column: 12, Selection: &Selection{...}},
|
||||||
BottomBar{CursorPos: "Ln 47, Col 12", WordWrap: true},
|
BottomBar{CursorPos: "Ln 47, Col 12", BytePos: "1024 / 50000", WordWrap: true},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -395,12 +395,13 @@ The search bar is only present when the user has activated search. When visible,
|
||||||
|
|
||||||
The StatusBar contains:
|
The StatusBar contains:
|
||||||
- **Filename** on line 1 (truncated with ellipsis if too long)
|
- **Filename** on line 1 (truncated with ellipsis if too long)
|
||||||
- **Action icons** (Cut, Copy, Search, Paste) on line 2, fixed positions
|
- **Action icons** (Cut, Copy, Paste) on line 2, left side
|
||||||
- **File size** between Paste and Conflict icons
|
- **Conflict icon** and **Search icon** on line 2, right side
|
||||||
|
|
||||||
The BottomBar contains:
|
The BottomBar contains:
|
||||||
- **Cursor position** on the left (e.g., "Ln 47, Col 12")
|
- **Cursor position** on the left (e.g., "Ln 47, Col 12")
|
||||||
- **Word wrap status** on the right (e.g., "Word Wrap: On")
|
- **Byte position** in the center (e.g., "1024 / 50000")
|
||||||
|
- **Word wrap button** on the right (tap to toggle On/Off)
|
||||||
|
|
||||||
### 8.3 Merge Page
|
### 8.3 Merge Page
|
||||||
|
|
||||||
|
|
|
||||||
45
doc/touch.md
45
doc/touch.md
|
|
@ -303,25 +303,24 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ filename.txt │ ← Line 1: filename (truncated with ellipsis)
|
│ filename.txt │ ← Line 1: filename (truncated with ellipsis)
|
||||||
│ [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf] │ ← Line 2: action icons + file size
|
│ [Cut] [Copy] [Paste] [Conf] [Search] │ ← Line 2: action icons (left/right)
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
StatusBar (top bar)
|
StatusBar (top bar)
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ TextField (editor content) │
|
│ TextField (editor content) │
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ Ln 10, Col 5 Word Wrap: On │ ← BottomBar
|
│ Ln 10, Col 5 1024 / 50000 [Word Wrap: On] │ ← BottomBar
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fixed slot positions** (in Dp, from the edges):
|
**Fixed slot positions** (in Dp, from the edges):
|
||||||
- **Cut icon**: leftmost action icon (24×24 DP, fixed position)
|
- **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)
|
- **Copy icon**: second from left (24×24 DP, fixed position, 36 DP from Cut icon)
|
||||||
- **Search icon**: third from left (24×24 DP, fixed position, 36 DP from Copy icon)
|
- **Paste 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**: right side (24×24 DP, fixed position, 36 DP from Search icon)
|
||||||
- **Conflict icon**: rightmost (24×24 DP, fixed position)
|
- **Search icon**: rightmost (24×24 DP, fixed position)
|
||||||
- **Filename**: top line, truncated with ellipsis if too long
|
- **Filename**: top line, truncated with ellipsis if too long
|
||||||
- **File size**: between Paste and Conflict icons
|
|
||||||
|
|
||||||
**Visibility rules**:
|
**Visibility rules**:
|
||||||
|
|
||||||
|
|
@ -329,9 +328,9 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Cut** | `selection_start != selection_end` |
|
| **Cut** | `selection_start != selection_end` |
|
||||||
| **Copy** | `selection_start != selection_end` |
|
| **Copy** | `selection_start != selection_end` |
|
||||||
| **Search** | Always visible (toggle search bar) |
|
|
||||||
| **Paste** | `clipboard != ""` |
|
| **Paste** | `clipboard != ""` |
|
||||||
| **Conflict** | sync conflict detected for active file |
|
| **Conflict** | sync conflict detected for active file |
|
||||||
|
| **Search** | Always visible (toggle search bar) |
|
||||||
|
|
||||||
Icons are rendered as `Button` elements with fixed sizes. The StatusBar's `Region` height is computed dynamically based on whether the filename line is visible (2 lines when filename is shown, 1 line when in merge/search mode).
|
Icons are rendered as `Button` elements with fixed sizes. The StatusBar's `Region` height is computed dynamically based on whether the filename line is visible (2 lines when filename is shown, 1 line when in merge/search mode).
|
||||||
|
|
||||||
|
|
@ -433,31 +432,32 @@ This field is **not** persisted to disk — it is reset on app restart (same as
|
||||||
In the truncated view, the StatusBar has 2 lines:
|
In the truncated view, the StatusBar has 2 lines:
|
||||||
```
|
```
|
||||||
Line 1: filename.txt...
|
Line 1: filename.txt...
|
||||||
Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf]
|
Line 2: [Cut] [Copy] [Paste] [Conf] [Search]
|
||||||
```
|
```
|
||||||
|
|
||||||
In the full view, the StatusBar has 3+ lines (depending on filename length):
|
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 1: very_long_filename_that_does_not_fit_on_a_single_line.txt
|
||||||
Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf]
|
Line 2: [Cut] [Copy] [Paste] [Conf] [Search]
|
||||||
```
|
```
|
||||||
|
|
||||||
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).
|
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
|
## 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).
|
The Bottom Bar appears at the bottom of the editor page. It displays cursor position, byte position, and word wrap status. It is always visible.
|
||||||
|
|
||||||
### 5.8.1 Layout
|
### 5.8.1 Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ Ln 10, Col 5 Word Wrap: On │
|
│ Ln 10, Col 5 1024 / 50000 [Word Wrap: On] │
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Left**: Cursor position (e.g., "Ln 10, Col 5")
|
- **Left**: Cursor position (e.g., "Ln 10, Col 5")
|
||||||
- **Right**: Word wrap status (e.g., "Word Wrap: On")
|
- **Center**: Byte position (e.g., "1024 / 50000")
|
||||||
|
- **Right**: Word wrap button (tap to toggle On/Off)
|
||||||
|
|
||||||
The BottomBar's `Region.H` is fixed at 24 DP. It sits below the editor content.
|
The BottomBar's `Region.H` is fixed at 24 DP. It sits below the editor content.
|
||||||
|
|
||||||
|
|
@ -468,13 +468,28 @@ The cursor position is computed from the current byte offset:
|
||||||
2. The `CursorPos` field is set to `"Ln {line}, Col {column}"`.
|
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.).
|
3. The field is updated on every cursor movement (tap, arrow keys, backspace, etc.).
|
||||||
|
|
||||||
### 5.8.3 Word Wrap Status
|
### 5.8.3 Byte Position
|
||||||
|
|
||||||
The word wrap status is a simple boolean field (`word_wrap_enabled`):
|
The byte position shows the current byte offset and total file size:
|
||||||
|
- **Format**: `"current / total"` (e.g., "1024 / 50000")
|
||||||
|
- **Current**: byte offset of the cursor in the file
|
||||||
|
- **Total**: total file size in bytes
|
||||||
|
- The field is updated on every cursor movement.
|
||||||
|
|
||||||
|
### 5.8.4 Word Wrap Button
|
||||||
|
|
||||||
|
The word wrap button toggles word wrap on/off:
|
||||||
- `true` → "Word Wrap: On"
|
- `true` → "Word Wrap: On"
|
||||||
- `false` → "Word Wrap: Off"
|
- `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).
|
**Interaction**:
|
||||||
|
1. User taps the word wrap button in the BottomBar.
|
||||||
|
2. Main goroutine receives `pointer.Event` (Type: `Press`) with the button's tag.
|
||||||
|
3. Main goroutine sends `InputEvent{ElementID: "word_wrap"}` to Logic.
|
||||||
|
4. Logic toggles the `word_wrap_enabled` state field.
|
||||||
|
5. Logic produces a new frame (BottomBar shows updated status).
|
||||||
|
|
||||||
|
The word wrap status is persisted to `.pad/state.json` and restored on app start.
|
||||||
|
|
||||||
## 6. Scroll Momentum
|
## 6. Scroll Momentum
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user