GUI redesign: status bar, fkey bar, color scheme

- Status bar: white-on-blue (was unreadable black-on-cyan with bold)
  Layout: left=TermTCP version, center=host+elapsed, right=UTC time+LOG
- Function key bar at bottom: F1=Help F3=Connect F4=Disc F5=Forms
  F6=Log F10=Quit — alternating chip/label colors, always visible
- Wire up F1/F3/F4/F5/F6/F10 in handle_key() (no more Ctrl+A required)
- New CP_FKEY color pair (blue on white) for fkey chips

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
gui-redesign
Ryan Collier 3 weeks ago
parent 05e6ad3921
commit c0cf254034

@ -54,9 +54,10 @@
#define CP_YELLOW 4
#define CP_CYAN 5
#define CP_MAGENTA 6
#define CP_STATUS 7 /* black on cyan */
#define CP_INPUT 8 /* white on blue */
#define CP_SEP 9 /* cyan on black */
#define CP_STATUS 7 /* white on blue - status bar */
#define CP_INPUT 8 /* black on white - input area */
#define CP_SEP 9 /* cyan on black - separators */
#define CP_FKEY 10 /* blue on white - fkey chip label */
/* ── Host config ─────────────────────────────────────────── */
typedef struct {
@ -141,10 +142,11 @@ static char hist_save[INPUT_MAX]; /* saved input while browsing */
/* ── ncurses windows ─────────────────────────────────────── */
WINDOW *status_win = NULL;
WINDOW *out_win = NULL;
WINDOW *sep_win = NULL; /* "----- Monitor -----" between output and monitor */
WINDOW *sep_win = NULL; /* separator between monitor and output panes */
WINDOW *mon_win = NULL;
WINDOW *sep2_win = NULL; /* "----- Input -----" above input area */
WINDOW *sep2_win = NULL; /* separator above input area */
WINDOW *input_win = NULL;
WINDOW *fkey_win = NULL; /* function key hint bar at bottom */
/* ── Input buffer ────────────────────────────────────────── */
char input_buf[INPUT_MAX];
@ -684,9 +686,10 @@ void init_colors(void)
init_pair(CP_YELLOW, COLOR_YELLOW, COLOR_BLACK);
init_pair(CP_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(CP_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(CP_STATUS, COLOR_BLACK, COLOR_CYAN);
init_pair(CP_STATUS, COLOR_WHITE, COLOR_BLUE);
init_pair(CP_INPUT, COLOR_BLACK, COLOR_WHITE);
init_pair(CP_SEP, COLOR_CYAN, COLOR_BLACK);
init_pair(CP_FKEY, COLOR_BLUE, COLOR_WHITE);
}
@ -734,10 +737,11 @@ void create_windows(void)
if (mon_win) { delwin(mon_win); mon_win = NULL; }
if (sep2_win) { delwin(sep2_win); sep2_win = NULL; }
if (input_win) { delwin(input_win); input_win = NULL; }
if (fkey_win) { delwin(fkey_win); fkey_win = NULL; }
/* overhead = status(1) + sep2(1) + input(INPUT_OUTER)
/* overhead = status(1) + sep2(1) + input(INPUT_OUTER) + fkey(1)
* + sep(1) if monitor visible */
int overhead = 1 + 1 + INPUT_OUTER + (mon_visible ? 1 : 0);
int overhead = 1 + 1 + INPUT_OUTER + 1 + (mon_visible ? 1 : 0);
int content_rows = LINES - overhead;
if (content_rows < 4) content_rows = 4;
@ -789,33 +793,83 @@ void create_windows(void)
leaveok(input_win, FALSE);
keypad(input_win, TRUE);
nodelay(input_win, TRUE);
row += INPUT_OUTER;
/* Function key hint bar */
fkey_win = newwin(1, COLS, row, 0);
wbkgd(fkey_win, COLOR_PAIR(CP_STATUS));
leaveok(fkey_win, TRUE);
}
void draw_status(void)
{
if (!status_win) return;
werase(status_win);
wattron(status_win, COLOR_PAIR(CP_STATUS) | A_BOLD);
wbkgd(status_win, COLOR_PAIR(CP_STATUS));
wattron(status_win, COLOR_PAIR(CP_STATUS));
/* Left: program name */
mvwprintw(status_win, 0, 1, "TermTCP %s", VERSION);
/* Center: connection info */
char center[80];
if (connected && current_host >= 0) {
int elapsed = (int)(time(NULL) - connect_time);
mvwprintw(status_win, 0, 0,
" TermTCP v%s | %s | %02d:%02d | Mon:%s%s | Ctrl+A=Menu",
VERSION,
hosts[current_host].name,
elapsed / 60, elapsed % 60,
mon_visible ? "ON" : "OFF",
logging ? " | LOG" : "");
snprintf(center, sizeof(center), "%s [%02d:%02d]",
hosts[current_host].name, elapsed / 60, elapsed % 60);
} else {
mvwprintw(status_win, 0, 0,
" TermTCP v%s | Not connected | Mon:%s | Ctrl+A=Menu",
VERSION, mon_visible ? "ON" : "OFF");
snprintf(center, sizeof(center), "Not Connected");
}
int cx = (COLS - (int)strlen(center)) / 2;
if (cx > 0) mvwprintw(status_win, 0, cx, "%s", center);
/* Right: UTC time + log indicator */
time_t now = time(NULL);
struct tm *t = gmtime(&now);
char right[32];
snprintf(right, sizeof(right), "%s%02d:%02d UTC ",
logging ? "LOG " : "", t->tm_hour, t->tm_min);
int rx = COLS - (int)strlen(right);
if (rx > 0) mvwprintw(status_win, 0, rx, "%s", right);
wattroff(status_win, COLOR_PAIR(CP_STATUS) | A_BOLD);
wattroff(status_win, COLOR_PAIR(CP_STATUS));
wrefresh(status_win);
}
static void draw_fkeys(void)
{
if (!fkey_win) return;
werase(fkey_win);
static const struct { const char *key; const char *desc; } fkeys[] = {
{ "F1", "Help" },
{ "F3", "Connect" },
{ "F4", "Disconnect" },
{ "F5", "Forms" },
{ "F6", "Log" },
{ "F10", "Quit" },
};
static const int nfkeys = 6;
int col = 0;
for (int i = 0; i < nfkeys && col < COLS - 2; i++) {
wattron(fkey_win, COLOR_PAIR(CP_FKEY) | A_BOLD);
mvwprintw(fkey_win, 0, col, "%s", fkeys[i].key);
col += (int)strlen(fkeys[i].key);
wattroff(fkey_win, COLOR_PAIR(CP_FKEY) | A_BOLD);
wattron(fkey_win, COLOR_PAIR(CP_STATUS));
mvwprintw(fkey_win, 0, col, " %-*s", (int)strlen(fkeys[i].desc) + 1, fkeys[i].desc);
col += (int)strlen(fkeys[i].desc) + 2;
wattroff(fkey_win, COLOR_PAIR(CP_STATUS));
}
/* Fill remainder of bar */
wattron(fkey_win, COLOR_PAIR(CP_STATUS));
for (int c = col; c < COLS; c++) mvwaddch(fkey_win, 0, c, ' ');
wattroff(fkey_win, COLOR_PAIR(CP_STATUS));
wrefresh(fkey_win);
}
/* Render stored lines from a ring buffer into an ncurses window.
* scroll_off=0 shows the most recent lines (live); >0 scrolls back. */
static void scrl_draw_window(WINDOW *win, ScrlLine *buf, int count, int head,
@ -1037,6 +1091,7 @@ static void refresh_all(void)
scrl_redraw_out();
scrl_redraw_mon();
draw_input();
draw_fkeys();
}
/* Full background repaint using redrawwin() — safe alternative to
@ -1049,6 +1104,7 @@ static void force_repaint(void)
if (mon_win) redrawwin(mon_win);
if (sep2_win) redrawwin(sep2_win);
if (input_win) redrawwin(input_win);
if (fkey_win) redrawwin(fkey_win);
refresh_all();
}
@ -2756,6 +2812,50 @@ static void handle_key(int ch)
ctrl_a_menu();
return;
case KEY_F(1):
show_help();
return;
case KEY_F(3): {
int idx = pick_host("Select Host");
if (idx >= 0) do_connect(idx);
return;
}
case KEY_F(4):
if (connected) {
tcp_disconnect();
append_out("*** Disconnected\n", 17, COLOR_PAIR(CP_RED));
draw_status();
}
return;
case KEY_F(5):
forms_menu();
return;
case KEY_F(6):
if (logging) {
close_log();
append_out("[Logging OFF]\n", 14, COLOR_PAIR(CP_YELLOW));
} else if (connected && current_host >= 0) {
char prefix[120];
snprintf(prefix, sizeof(prefix), "%s_%s",
hosts[current_host].host, hosts[current_host].port);
open_log(prefix);
append_out("[Logging ON]\n", 13, COLOR_PAIR(CP_YELLOW));
} else {
append_out("Connect first to start logging.\n", 32, COLOR_PAIR(CP_YELLOW));
}
draw_status();
return;
case KEY_F(10):
if (connected) tcp_disconnect();
if (logging) close_log();
endwin();
exit(0);
case KEY_RESIZE:
endwin(); refresh(); clear();
create_windows();

Loading…
Cancel
Save

Powered by TurnKey Linux.