Render help screen centered on terminal.
234 {
235 if (!ctx) {
236 return;
237 }
238
239
240 int term_width = (int)GET_OPTION(width);
241 int term_height = (int)GET_OPTION(height);
242
243
244 if (term_width < 50 || term_height < 20) {
245
246 const char *msg = "\n[Terminal too small for help screen - try resizing]\n";
248 return;
249 }
250
251
252
253 const int box_width = 48;
254 const int box_height = 24;
255
256
257
258 int start_col = (term_width - box_width) / 2;
259 if (start_col < 0) {
260 start_col = 0;
261 }
262
263
264 int start_row = (term_height - box_height) / 2;
265 if (start_row < 1) {
266 start_row = 1;
267 }
268
269
270 const size_t BUFFER_SIZE = 8192;
271 char *buffer = SAFE_MALLOC(BUFFER_SIZE, char *);
272 size_t buf_pos = 0;
273
274#define APPEND(fmt, ...) \
275 do { \
276 int written = snprintf(buffer + buf_pos, BUFFER_SIZE - buf_pos, fmt, ##__VA_ARGS__); \
277 if (written > 0) { \
278 buf_pos += written; \
279 } \
280 } while (0)
281
282
285
286
287 char line_buf[256];
288
289
290 APPEND(
"\033[%d;%dH", start_row + 1, start_col + 1);
291 APPEND(
"╔══════════════════════════════════════════════╗");
292
293
294 APPEND(
"\033[%d;%dH", start_row + 2, start_col + 1);
295 build_help_line(line_buf, sizeof(line_buf), "ascii-chat Keyboard Shortcuts");
297
298
299 APPEND(
"\033[%d;%dH", start_row + 3, start_col + 1);
300 APPEND(
"╠══════════════════════════════════════════════╣");
301
302
303 APPEND(
"\033[%d;%dH", start_row + 4, start_col + 1);
304 build_help_line(line_buf, sizeof(line_buf), "Navigation & Control:");
306
307 APPEND(
"\033[%d;%dH", start_row + 5, start_col + 1);
308 build_help_line(line_buf, sizeof(line_buf), "─────────────────────");
310
311 APPEND(
"\033[%d;%dH", start_row + 6, start_col + 1);
312 build_help_line(line_buf, sizeof(line_buf), "? Toggle this help screen");
314
315 APPEND(
"\033[%d;%dH", start_row + 7, start_col + 1);
316 build_help_line(line_buf, sizeof(line_buf), "Space Play/Pause (files only)");
318
319 APPEND(
"\033[%d;%dH", start_row + 8, start_col + 1);
320 build_help_line(line_buf, sizeof(line_buf), "← / → Seek backward/forward 30s");
322
323 APPEND(
"\033[%d;%dH", start_row + 9, start_col + 1);
324 build_help_line(line_buf, sizeof(line_buf), "m Mute/Unmute audio");
326
327 APPEND(
"\033[%d;%dH", start_row + 10, start_col + 1);
328 build_help_line(line_buf, sizeof(line_buf), "↑ / ↓ Volume up/down (10%)");
330
331 APPEND(
"\033[%d;%dH", start_row + 11, start_col + 1);
332 build_help_line(line_buf, sizeof(line_buf), "c Cycle color mode");
334
335 APPEND(
"\033[%d;%dH", start_row + 12, start_col + 1);
336 build_help_line(line_buf, sizeof(line_buf), "f Flip webcam horizontally");
338
339 APPEND(
"\033[%d;%dH", start_row + 13, start_col + 1);
340 build_help_line(line_buf, sizeof(line_buf), "r Cycle render mode");
342
343#ifndef NDEBUG
344 APPEND(
"\033[%d;%dH", start_row + 14, start_col + 1);
345 build_help_line(line_buf, sizeof(line_buf), "Ctrl+L Print held lock state");
347
348
349 APPEND(
"\033[%d;%dH", start_row + 15, start_col + 1);
350 build_help_line(line_buf, sizeof(line_buf), "");
352
353
354 APPEND(
"\033[%d;%dH", start_row + 16, start_col + 1);
355 build_help_line(line_buf, sizeof(line_buf), "Current Settings:");
357
358 APPEND(
"\033[%d;%dH", start_row + 17, start_col + 1);
359 build_help_line(line_buf, sizeof(line_buf), "───────────────");
361#else
362
363 APPEND(
"\033[%d;%dH", start_row + 14, start_col + 1);
364 build_help_line(line_buf, sizeof(line_buf), "");
366
367
368 APPEND(
"\033[%d;%dH", start_row + 15, start_col + 1);
369 build_help_line(line_buf, sizeof(line_buf), "Current Settings:");
371
372 APPEND(
"\033[%d;%dH", start_row + 16, start_col + 1);
373 build_help_line(line_buf, sizeof(line_buf), "───────────────");
375#endif
376
377
378 APPEND(
"\033[%d;%dH", start_row + 15, start_col + 1);
379 build_help_line(line_buf, sizeof(line_buf), "Current Settings:");
381
382 APPEND(
"\033[%d;%dH", start_row + 16, start_col + 1);
383 build_help_line(line_buf, sizeof(line_buf), "───────────────");
385
386
387 double current_volume = GET_OPTION(speakers_volume);
388 int current_color_mode = (int)GET_OPTION(color_mode);
389 int current_render_mode = (int)GET_OPTION(render_mode);
390 bool flip_x = (
bool)GET_OPTION(flip_x);
391 bool flip_y = (
bool)GET_OPTION(flip_y);
392 bool current_audio = (
bool)GET_OPTION(audio_enabled);
393
394
395 char volume_bar[32];
396 format_volume_bar(current_volume, volume_bar, sizeof(volume_bar));
397
398
401
402
403 const char *flip_text = "None";
404 if (flip_x && flip_y) {
406 } else if (flip_x) {
408 } else if (flip_y) {
410 } else {
412 }
413
414
415 const char *audio_text =
417
418
419#ifndef NDEBUG
420 APPEND(
"\033[%d;%dH", start_row + 18, start_col + 1);
421 build_settings_line(line_buf, sizeof(line_buf), "Audio", audio_text);
423
424 APPEND(
"\033[%d;%dH", start_row + 19, start_col + 1);
425 build_settings_line(line_buf, sizeof(line_buf), "Volume", volume_bar);
427
428 APPEND(
"\033[%d;%dH", start_row + 20, start_col + 1);
429 build_settings_line(line_buf, sizeof(line_buf), "Color", color_str);
431
432 APPEND(
"\033[%d;%dH", start_row + 21, start_col + 1);
433 build_settings_line(line_buf, sizeof(line_buf), "Render", render_str);
435
436 APPEND(
"\033[%d;%dH", start_row + 22, start_col + 1);
437 build_settings_line(line_buf, sizeof(line_buf), "Flip", flip_text);
439
440
441 APPEND(
"\033[%d;%dH", start_row + 23, start_col + 1);
442 build_help_line(line_buf, sizeof(line_buf), "");
444
445
446 APPEND(
"\033[%d;%dH", start_row + 24, start_col + 1);
447 build_help_line(line_buf, sizeof(line_buf), "Press ? to close");
449
450
451 APPEND(
"\033[%d;%dH", start_row + 25, start_col + 1);
452 APPEND(
"╚══════════════════════════════════════════════╝");
453#else
454 APPEND(
"\033[%d;%dH", start_row + 17, start_col + 1);
455 build_settings_line(line_buf, sizeof(line_buf), "Audio", audio_text);
457
458 APPEND(
"\033[%d;%dH", start_row + 18, start_col + 1);
459 build_settings_line(line_buf, sizeof(line_buf), "Volume", volume_bar);
461
462 APPEND(
"\033[%d;%dH", start_row + 19, start_col + 1);
463 build_settings_line(line_buf, sizeof(line_buf), "Color", color_str);
465
466 APPEND(
"\033[%d;%dH", start_row + 20, start_col + 1);
467 build_settings_line(line_buf, sizeof(line_buf), "Render", render_str);
469
470 APPEND(
"\033[%d;%dH", start_row + 21, start_col + 1);
471 build_settings_line(line_buf, sizeof(line_buf), "Flip", flip_text);
473
474
475 APPEND(
"\033[%d;%dH", start_row + 22, start_col + 1);
476 build_help_line(line_buf, sizeof(line_buf), "");
478
479
480 APPEND(
"\033[%d;%dH", start_row + 23, start_col + 1);
481 build_help_line(line_buf, sizeof(line_buf), "Press ? to close");
483
484
485 APPEND(
"\033[%d;%dH", start_row + 24, start_col + 1);
486 APPEND(
"╚══════════════════════════════════════════════╝");
487#endif
488
489
490#ifndef NDEBUG
491 APPEND(
"\033[%d;%dH", start_row + 26, start_col + 1);
492#else
493 APPEND(
"\033[%d;%dH", start_row + 25, start_col + 1);
494#endif
495
496#undef APPEND
497
498
500
501
504 if (tty_fd >= 0) {
506 }
507 }
508
509 SAFE_FREE(buffer);
510}
void session_display_write_raw(session_display_ctx_t *ctx, const char *data, size_t len)
bool session_display_has_tty(session_display_ctx_t *ctx)
int session_display_get_tty_fd(session_display_ctx_t *ctx)
const char * color_mode_to_string(terminal_color_mode_t mode)
const char * render_mode_to_string(render_mode_t mode)
const char * colored_string(log_color_t color, const char *text)