ui(console): center menu in a bordered box with better spacing

Both renderers now draw the menu inside a centered box with:
- Rounded corners (modern) / box-drawing (VT220)
- Title centered inside the box top
- Section separators as horizontal lines within the box
- Selected item highlighted across the full box width
- Vertical and horizontal centering on screen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 02:31:54 +00:00
parent a3aa2a7608
commit 7866194e65
2 changed files with 103 additions and 29 deletions

View File

@@ -167,17 +167,42 @@ class CursesRenderer(BaseRenderer):
def draw_menu(self, items, selected_index=0, title=''):
h, w = self.get_size()
start_row = 3
# Calculate menu dimensions for centering
item_count = len(items)
# Find widest label for box sizing
max_label = 0
for num, label in items:
if num != "---" and num != "\u2500":
max_label = max(max_label, len(f" {num}. {label} "))
box_w = max(max_label + 8, 44)
box_w = min(box_w, w - 4)
box_h = item_count + 4 # top/bottom border + title + blank line
if title:
self._safe_addstr(start_row, 2, title, self._attr("title"))
start_row += 2
box_h += 2
visible = h - start_row - 3 # leave room for footer
if visible < 1:
return
# Center the box vertically and horizontally
start_row = max((h - box_h) // 2 - 1, 2)
start_col = max((w - box_w) // 2, 1)
# Scrolling offset
# Draw box
self.draw_box(start_row, start_col, box_h, box_w, "")
row = start_row + 1
if title:
# Title centered inside the box
title_col = start_col + max((box_w - len(title)) // 2, 2)
self._safe_addstr(row, title_col, title,
self._attr("title"))
row += 1
self._hline(row, start_col + 1, box_w - 2)
row += 1
# Menu items inside the box
inner_left = start_col + 3
inner_w = box_w - 6
visible = box_h - (row - start_row) - 1
offset = 0
if selected_index >= visible:
offset = selected_index - visible + 1
@@ -188,19 +213,20 @@ class CursesRenderer(BaseRenderer):
break
if idx < offset:
continue
row = start_row + drawn
# Separator
if num == "\u2500" or num == "---":
self._hline(row, 2, w - 4)
self._hline(row, start_col + 1, box_w - 2)
row += 1
drawn += 1
continue
marker = "\u25b8 " if idx == selected_index else " "
text = f"{marker}{num}. {label}"
style = "highlight" if idx == selected_index else "normal"
self._safe_addstr(row, 2, pad_right(text, w - 4),
self._safe_addstr(row, inner_left, pad_right(text, inner_w),
self._attr(style))
row += 1
drawn += 1
def draw_table(self, headers, rows, widths, page_info=None,