mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:54:38 +08:00
tui: framed welcome banner before username prompt (M7-1)
Replace the four lines of `==` rules + bilingual title with a centred
rounded box so the eye lands on a single visual element instead of two.
The new tui_render_welcome():
- centres horizontally and vertically (about a third of the way down)
- shows TNT + version, then 中文 subtitle, then English caption with
decreasing visual weight (bold cyan / default / dim grey)
- falls back to a plain "TNT $version — anonymous chat over SSH" line
when the terminal is too narrow for the frame
- declared in tui.h, called from input.c read_username()
read_username()'s prompt becomes a single short bilingual hint
("请输入用户名 (留空 anonymous): ") that lives below the box.
This commit is contained in:
parent
7897d8820e
commit
159073ec49
3 changed files with 103 additions and 6 deletions
|
|
@ -22,6 +22,11 @@ void tui_render_input(struct client *client, const char *input);
|
|||
/* Clear the screen */
|
||||
void tui_clear_screen(struct client *client);
|
||||
|
||||
/* Render the pre-login welcome banner. Centered, framed, shown once before
|
||||
* the username prompt. Caller is responsible for printing the prompt
|
||||
* itself afterwards. */
|
||||
void tui_render_welcome(struct client *client);
|
||||
|
||||
/* Get help text based on language */
|
||||
const char* tui_get_help_text(help_lang_t lang);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,12 +27,8 @@ static int read_username(client_t *client) {
|
|||
int pos = 0;
|
||||
char buf[4];
|
||||
|
||||
tui_clear_screen(client);
|
||||
client_printf(client, "================================\r\n");
|
||||
client_printf(client, " 欢迎来到 TNT 匿名聊天室\r\n");
|
||||
client_printf(client, " Welcome to TNT Anonymous Chat\r\n");
|
||||
client_printf(client, "================================\r\n\r\n");
|
||||
client_printf(client, "请输入用户名 (留空默认为 anonymous): ");
|
||||
tui_render_welcome(client);
|
||||
client_printf(client, " 请输入用户名 (留空 anonymous): ");
|
||||
|
||||
while (1) {
|
||||
int n = ssh_channel_read_timeout(client->channel, buf, 1, 0, 60000); /* 60 sec timeout */
|
||||
|
|
|
|||
96
src/tui.c
96
src/tui.c
|
|
@ -118,6 +118,102 @@ void tui_clear_screen(client_t *client) {
|
|||
client_send(client, clear, strlen(clear));
|
||||
}
|
||||
|
||||
/* Render the pre-login welcome banner.
|
||||
*
|
||||
* Centred horizontally; vertically positioned about a third of the way down
|
||||
* the available height so the user's eye lands naturally on it before the
|
||||
* prompt below. Uses light box-drawing characters (U+256D / U+2570) so the
|
||||
* frame matches the rest of the TUI's aesthetic instead of the older ASCII
|
||||
* `==` rules. */
|
||||
void tui_render_welcome(client_t *client) {
|
||||
if (!client || !client->connected) return;
|
||||
|
||||
int rw = client->width;
|
||||
int rh = client->height;
|
||||
if (rw < 10) rw = 10;
|
||||
if (rh < 4) rh = 4;
|
||||
|
||||
/* Lines, in display order. Width is computed in display columns. */
|
||||
const char *line1 = "TNT · " TNT_VERSION;
|
||||
const char *line2 = "匿名聊天室 · SSH";
|
||||
const char *line3 = "Anonymous chat over SSH";
|
||||
|
||||
int inner_w = utf8_string_width(line1);
|
||||
int w2 = utf8_string_width(line2);
|
||||
int w3 = utf8_string_width(line3);
|
||||
if (w2 > inner_w) inner_w = w2;
|
||||
if (w3 > inner_w) inner_w = w3;
|
||||
inner_w += 4; /* 2 columns padding on each side */
|
||||
|
||||
/* Fall back to plain prompt if the terminal is too narrow for the frame. */
|
||||
if (inner_w + 2 > rw) {
|
||||
char fallback[128];
|
||||
int n = snprintf(fallback, sizeof(fallback),
|
||||
ANSI_CLEAR ANSI_HOME
|
||||
"TNT %s — anonymous chat over SSH\r\n\r\n",
|
||||
TNT_VERSION);
|
||||
if (n > 0) client_send(client, fallback, (size_t)n);
|
||||
return;
|
||||
}
|
||||
|
||||
int top_pad = rh / 3;
|
||||
if (top_pad < 1) top_pad = 1;
|
||||
int left_pad = (rw - (inner_w + 2)) / 2;
|
||||
if (left_pad < 0) left_pad = 0;
|
||||
|
||||
/* ~5 KiB is plenty for the framed banner even on the largest terminals. */
|
||||
char buf[4096];
|
||||
size_t pos = 0;
|
||||
|
||||
buffer_appendf(buf, sizeof(buf), &pos, ANSI_CLEAR ANSI_HOME);
|
||||
for (int i = 0; i < top_pad; i++) {
|
||||
buffer_appendf(buf, sizeof(buf), &pos, "\r\n");
|
||||
}
|
||||
|
||||
/* Top border: ╭───…───╮ */
|
||||
for (int i = 0; i < left_pad; i++) buffer_append_bytes(buf, sizeof(buf), &pos, " ", 1);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[36m", 5);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "╭", strlen("╭"));
|
||||
for (int i = 0; i < inner_w; i++) buffer_append_bytes(buf, sizeof(buf), &pos, "─", strlen("─"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "╮", strlen("╮"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[0m", 4);
|
||||
buffer_appendf(buf, sizeof(buf), &pos, "\r\n");
|
||||
|
||||
/* Three content lines with surrounding │ borders, centred inside the frame. */
|
||||
const char *lines[3] = {line1, line2, line3};
|
||||
int widths[3] = {utf8_string_width(line1), w2, w3};
|
||||
const char *line_color[3] = {"\033[1;36m", "\033[0m", "\033[2;37m"};
|
||||
for (int li = 0; li < 3; li++) {
|
||||
for (int i = 0; i < left_pad; i++) buffer_append_bytes(buf, sizeof(buf), &pos, " ", 1);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[36m", 5);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "│", strlen("│"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[0m", 4);
|
||||
|
||||
int pad_total = inner_w - widths[li];
|
||||
int pad_left = pad_total / 2;
|
||||
int pad_right = pad_total - pad_left;
|
||||
for (int i = 0; i < pad_left; i++) buffer_append_bytes(buf, sizeof(buf), &pos, " ", 1);
|
||||
buffer_appendf(buf, sizeof(buf), &pos, "%s%s\033[0m", line_color[li], lines[li]);
|
||||
for (int i = 0; i < pad_right; i++) buffer_append_bytes(buf, sizeof(buf), &pos, " ", 1);
|
||||
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[36m", 5);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "│", strlen("│"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[0m", 4);
|
||||
buffer_appendf(buf, sizeof(buf), &pos, "\r\n");
|
||||
}
|
||||
|
||||
/* Bottom border: ╰───…───╯ */
|
||||
for (int i = 0; i < left_pad; i++) buffer_append_bytes(buf, sizeof(buf), &pos, " ", 1);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[36m", 5);
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "╰", strlen("╰"));
|
||||
for (int i = 0; i < inner_w; i++) buffer_append_bytes(buf, sizeof(buf), &pos, "─", strlen("─"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "╯", strlen("╯"));
|
||||
buffer_append_bytes(buf, sizeof(buf), &pos, "\033[0m", 4);
|
||||
buffer_appendf(buf, sizeof(buf), &pos, "\r\n\r\n");
|
||||
|
||||
client_send(client, buf, pos);
|
||||
}
|
||||
|
||||
/* Render the main screen */
|
||||
void tui_render_screen(client_t *client) {
|
||||
if (!client || !client->connected) return;
|
||||
|
|
|
|||
Loading…
Reference in a new issue