ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
session.h File Reference

Go to the source code of this file.

Data Structures

struct  ui_discovery_view_t
struct  ui_splash_view_t
struct  ui_session_view_t

Macros

#define TUI_SESSION_SESSION_STRING_BUFFER_SIZE   256
#define TUI_SESSION_UPDATE_NOTIFICATION_BUFFER_SIZE   1024
#define TUI_SESSION_CONNECTION_TARGET_BUFFER_SIZE   512

Typedefs

typedef struct ui_session ui_session_t
typedef void(* ui_session_draw_fn) (frame_buffer_t *output, terminal_size_t size, const animation_sample_t *animation, void *context)
 The useful part of ui session view is in screen, minimum, dirty, clear: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path.

Enumerations

enum  ui_session_action_t {
  UI_ACTION_NONE , UI_ACTION_SETTINGS , UI_ACTION_HELP , UI_ACTION_CLOSE ,
  UI_ACTION_SEEK_BACK , UI_ACTION_SEEK_FORWARD , UI_ACTION_PAUSE , UI_ACTION_VOLUME ,
  UI_ACTION_DEBUG , UI_ACTION_LOGS , UI_ACTION_TOGGLE_MEDIA , UI_ACTION_QUIT ,
  UI_ACTION_FORCE_QUIT
}

Functions

void ui_session_splash_render (frame_buffer_t *buf, terminal_size_t size, void *view)
char * ui_session_help_render (terminal_size_t size, bool has_media, bool browser, terminal_size_t *minimum)
void ui_session_help_free (char *text)
char * ui_session_context_help_render (terminal_size_t size, ui_screen_t screen, terminal_size_t *minimum)
ui_session_action_t ui_session_key (keyboard_key_t key, double *saved_volume)
terminal_size_t ui_session_size (const ui_session_t *session)
int ui_session_select_screen (uint32_t visible_screens)
const char * ui_session_render (ui_session_t *session, const ui_session_view_t *view, uint64_t now_ns)
bool ui_session_is_covered (const ui_session_t *session)
size_t ui_session_frame_length (const ui_session_t *session)
uint64_t ui_session_next_frame_ns (const ui_session_t *session)
ui_session_t * ui_session_create (void)
void ui_session_destroy (ui_session_t *session)
void ui_session_resize (ui_session_t *session, int cols, int rows)
void ui_session_loading (ui_session_t *session, bool loading, const char *message)
void ui_session_log (ui_session_t *session, const char *message)
asciichat_error_t ui_session_media (ui_session_t *session, const char *data, size_t length)
ui_session_action_t ui_session_input (ui_session_t *session, keyboard_key_t key)
const char * ui_session_tick (ui_session_t *session, uint64_t now_ns)
void ui_session_clear (ui_session_t *session)
void ui_session_redraw (ui_session_t *session)
void ui_session_logs_render (frame_buffer_t *output, terminal_size_t size, ui_session_t *session)
bool ui_session_logs_key (keyboard_key_t key)
void ui_session_capture_logs (ui_session_t *session)

Macro Definition Documentation

◆ TUI_SESSION_CONNECTION_TARGET_BUFFER_SIZE

#define TUI_SESSION_CONNECTION_TARGET_BUFFER_SIZE   512

Definition at line 6 of file include/ascii-chat/tui/session.h.

◆ TUI_SESSION_SESSION_STRING_BUFFER_SIZE

#define TUI_SESSION_SESSION_STRING_BUFFER_SIZE   256

Definition at line 4 of file include/ascii-chat/tui/session.h.

◆ TUI_SESSION_UPDATE_NOTIFICATION_BUFFER_SIZE

#define TUI_SESSION_UPDATE_NOTIFICATION_BUFFER_SIZE   1024

Definition at line 5 of file include/ascii-chat/tui/session.h.

Typedef Documentation

◆ ui_session_draw_fn

typedef void(* ui_session_draw_fn) (frame_buffer_t *output, terminal_size_t size, const animation_sample_t *animation, void *context)

The useful part of ui session view is in screen, minimum, dirty, clear: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path.

A borrowed view, valid for the duration of ui_session_render(). Hosts retain

The useful part of ui session view is in screen, minimum, dirty, clear: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path. snapshots and serialize access to a session; callbacks must not recurse into its renderer. The runtime owns selection policy, transitions and animation.

Definition at line 64 of file include/ascii-chat/tui/session.h.

◆ ui_session_t

typedef struct ui_session ui_session_t

Definition at line 56 of file include/ascii-chat/tui/session.h.

Enumeration Type Documentation

◆ ui_session_action_t

Enumerator
UI_ACTION_NONE 
UI_ACTION_SETTINGS 
UI_ACTION_HELP 
UI_ACTION_CLOSE 
UI_ACTION_SEEK_BACK 
UI_ACTION_SEEK_FORWARD 
UI_ACTION_PAUSE 
UI_ACTION_VOLUME 
UI_ACTION_DEBUG 
UI_ACTION_LOGS 
UI_ACTION_TOGGLE_MEDIA 
UI_ACTION_QUIT 
UI_ACTION_FORCE_QUIT 

Definition at line 37 of file include/ascii-chat/tui/session.h.

Function Documentation

◆ ui_session_capture_logs()

void ui_session_capture_logs ( ui_session_t * session)

Attach this instance to the module's existing C logger. Detaches on destruction.

Definition at line 375 of file lib/tui/session.c.

375 {
376 if (s)
378}
void log_set_session_log_buffer(session_log_buffer_t *buf)
Register a session log buffer with the logger.
Definition log.c:2048

References log_set_session_log_buffer(), and ui_session::logs.

Referenced by SessionUiBinding::SessionUiBinding().

◆ ui_session_clear()

void ui_session_clear ( ui_session_t * session)

Definition at line 357 of file lib/tui/session.c.

357 {
358 if (s) {
359 frame_buffer_reset(s->media);
360 s->help = false;
361 s->show_logs = false;
362 s->dirty = true;
363 }
364}
void frame_buffer_reset(frame_buffer_t *buf)
Clear buffer contents while keeping allocation.

References ui_session::dirty, frame_buffer_reset(), ui_session::help, ui_session::media, and ui_session::show_logs.

Referenced by SessionUiBinding::clear().

◆ ui_session_context_help_render()

char * ui_session_context_help_render ( terminal_size_t size,
ui_screen_t screen,
terminal_size_t * minimum )

Definition at line 251 of file session_help.c.

251 {
252 if (!minimum) {
253 SET_ERRNO(ERROR_INVALID_PARAM, "Help minimum geometry output is required");
254 return NULL;
255 }
256 static const ui_help_entry_t sync[] = {{"0 / Esc", "Close sync viewer"},
257 {"Up / Down", "Select primitive"},
258 {"Left / Right", "Previous/next page"},
259 {"Home / End", "First/last primitive"},
260 {"=", "Running app statistics"},
261 {"]", "Log viewer"},
262 {"?", "Close this help"}};
263 static const ui_help_entry_t stats[] = {{"= / Esc", "Close statistics"},
264 {"Tab / Left / Right", "Switch data page"},
265 {"Up / Down", "Select and scroll rows"},
266 {"Home / End", "First/last row"},
267 {"0", "Sync primitives"},
268 {"]", "Log viewer"},
269 {"?", "Close this help"}};
270 static const ui_help_entry_t errors[] = {
271 {"` / Esc", "Close error stacks"}, {"Tab", "Current/history page"}, {"Up / Down", "Select and scroll errors"},
272 {"s", "Change sort order"}, {"x", "Clear selected error"}, {"=", "Running app statistics"},
273 {"0", "Sync primitives"}, {"?", "Close this help"}};
274 static const ui_help_entry_t update[] = {{"F12 / Esc", "Close update checker"},
275 {"Left / Right / Tab", "Select button"},
276 {"Enter", "Activate selected button"},
277 {"O", "Open release page"},
278 {"R", "Check again"},
279 {"?", "Close this help"}};
280 static const ui_help_entry_t lan[] = {{"Up / Down / j / k", "Select LAN server"},
281 {"0-9", "Enter server number"},
282 {"Enter", "Connect to selected server"},
283 {"Esc", "Cancel LAN selection"},
284 {"=", "Running app statistics"},
285 {"0", "Sync primitives"},
286 {"?", "Close this help"}};
287 static const ui_help_entry_t media[] = {
288 {"Enter", "Play the entered paths or URLs"}, {"Esc / Ctrl-O", "Cancel media input"},
289 {"Left / Right", "Move the text cursor"}, {"Home / End", "Beginning/end of input"},
290 {"Backspace / Delete", "Delete a character"}, {"?", "Help when the input is empty"}};
291 const ui_help_entry_t *entries = NULL;
292 size_t count = 0;
293 const char *title = NULL;
294 switch (screen) {
295 case UI_SCREEN_ERROR: {
296 static const ui_help_entry_t popup[] = {{"Left / Right", "Previous / next error"},
297 {"Home / End", "First / last error"},
298 {"Up / Down", "Scroll error details"},
299 {"PgUp / PgDn", "Scroll a page"},
300 {"Enter / Esc", "Dismiss all errors"},
301 {"q", "Dismiss all errors"},
302 {"?", "Close this help"}};
303 entries = popup;
304 count = sizeof(popup) / sizeof(*popup);
305 title = "Error Popup Keyboard Shortcuts";
306 break;
307 }
308 case UI_SCREEN_SYNC:
309 entries = sync;
310 count = sizeof(sync) / sizeof(*sync);
311 title = "Sync Viewer Keyboard Shortcuts";
312 break;
313 case UI_SCREEN_STATS:
314 entries = stats;
315 count = sizeof(stats) / sizeof(*stats);
316 title = "Statistics Keyboard Shortcuts";
317 break;
318 case UI_SCREEN_ERRNO:
319 entries = errors;
320 count = sizeof(errors) / sizeof(*errors);
321 title = "Error Stacks Keyboard Shortcuts";
322 break;
323 case UI_SCREEN_PROMPT:
324 entries = media;
325 count = sizeof(media) / sizeof(*media);
326 title = "Media Input Keyboard Shortcuts";
327 break;
328 case UI_SCREEN_MDNS:
329 entries = lan;
330 count = sizeof(lan) / sizeof(*lan);
331 title = "LAN Selection Keyboard Shortcuts";
332 break;
333 case UI_SCREEN_UPDATE:
334 entries = update;
335 count = sizeof(update) / sizeof(*update);
336 title = "Update Checker Keyboard Shortcuts";
337 break;
338 default:
339 return ui_session_help_render(size, GET_OPTION(media_file)[0] || GET_OPTION(media_url)[0], false, minimum);
340 }
342 snprintf(footer, sizeof(footer), "Press %s to close", colored_string(LOG_COLOR_WARN, "?"));
343 ui_help_menu_t menu = {.title = title, .entries = entries, .count = count, .footer = footer, .top_margin = 0};
344 *minimum = ui_help_menu_measure(&menu);
345 frame_buffer_t *buffer = frame_buffer_create(size.rows, size.cols);
346 if (!buffer)
347 return NULL;
348 ui_help_menu_render(buffer, size, &menu);
349 size_t length = frame_buffer_get_length(buffer);
350 char *result = SAFE_MALLOC(length + 1, char *);
351 memcpy(result, frame_buffer_get_content(buffer), length);
352 result[length] = '\0';
353 frame_buffer_destroy(buffer);
354 return result;
355}
#define SET_ERRNO(code,...)
void frame_buffer_destroy(frame_buffer_t *buf)
Destroy a frame buffer.
size_t frame_buffer_get_length(const frame_buffer_t *buf)
Get the current content length of the frame buffer.
const char * frame_buffer_get_content(const frame_buffer_t *buf)
Get a pointer to the buffer content.
frame_buffer_t * frame_buffer_create(int rows, int cols)
Create a new frame buffer.
struct frame_buffer frame_buffer_t
Opaque frame buffer handle.
#define SAFE_MALLOC(size, cast)
Definition common.h:265
@ ERROR_INVALID_PARAM
@ LOG_COLOR_WARN
Definition log/log.h:151
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Definition string.c:284
terminal_size_t ui_help_menu_measure(const ui_help_menu_t *m)
Definition help_menu.c:85
bool ui_help_menu_render(frame_buffer_t *out, terminal_size_t size, const ui_help_menu_t *m)
Definition help_menu.c:101
char * ui_session_help_render(terminal_size_t size, bool has_media, bool browser, terminal_size_t *minimum)
#define TUI_SESSION_HELP_FOOTER_BUFFER_SIZE
Definition session_help.c:6
Definition help_menu.h:3
ui help entry keeps the values that move through the subsystem: keys, description....
Definition help_menu.h:12
@ UI_SCREEN_PROMPT
@ UI_SCREEN_ERRNO
@ UI_SCREEN_STATS
@ UI_SCREEN_UPDATE
@ UI_SCREEN_SYNC
@ UI_SCREEN_MDNS
@ UI_SCREEN_ERROR

References colored_string(), ERROR_INVALID_PARAM, frame_buffer_create(), frame_buffer_destroy(), frame_buffer_get_content(), frame_buffer_get_length(), GET_OPTION, LOG_COLOR_WARN, SAFE_MALLOC, SET_ERRNO, TUI_SESSION_HELP_FOOTER_BUFFER_SIZE, ui_help_menu_measure(), ui_help_menu_render(), UI_SCREEN_ERRNO, UI_SCREEN_ERROR, UI_SCREEN_MDNS, UI_SCREEN_PROMPT, UI_SCREEN_STATS, UI_SCREEN_SYNC, UI_SCREEN_UPDATE, and ui_session_help_render().

Referenced by keyboard_help_toggle_terminal().

◆ ui_session_create()

ui_session_t * ui_session_create ( void )

Definition at line 46 of file lib/tui/session.c.

46 {
47 ui_session_t *s = SAFE_CALLOC(1, sizeof(*s), ui_session_t *);
48 if (!s)
49 return NULL;
50 s->frame = frame_buffer_create(24, 80);
51 s->media = frame_buffer_create(24, 80);
53 s->owns_logs = !s->logs;
54 if (s->owns_logs)
56 if (!s->frame || !s->media || !s->logs) {
58 return NULL;
59 }
60 s->started = time(NULL);
62 s->size = (terminal_size_t){.cols = 80, .rows = 24};
63 s->active = -1;
64 s->saved_volume = 1;
65 s->dirty = true;
66 s->splash.use_colors = true;
67 animation_init(&s->animation, "session_splash",
69 .type = ANIMATION_SPLASH_RAINBOW, .fps = 60, .speed = 1, .hidden_policy = ANIMATION_HIDDEN_PAUSE});
70 return s;
71}
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
struct ui_session ui_session_t
void ui_session_destroy(ui_session_t *s)
session_log_buffer_t * log_get_history_buffer(void)
Definition log.c:565
asciichat_error_t log_search_init(void)
Initialize interactive grep subsystem.
Definition search.c:144
session_log_buffer_t * session_log_buffer_create(void)
Create a new session log buffer instance.
frame_buffer_t * frame
ui_splash_view_t splash
animation_t animation
terminal_size_t size
session_log_buffer_t * logs
double saved_volume
frame_buffer_t * media
asciichat_error_t animation_init(animation_t *a, const char *name, animation_config_t config)

References ui_session::active, ui_session::animation, animation_init(), ui_session::dirty, ui_session::frame, frame_buffer_create(), log_get_history_buffer(), log_search_init(), ui_session::logs, ui_session::media, ui_session::owns_logs, SAFE_CALLOC, ui_session::saved_volume, session_log_buffer_create(), ui_session::size, ui_session::splash, ui_session::started, ui_session_destroy(), and ui_splash_view_t::use_colors.

Referenced by SessionUiBinding::SessionUiBinding().

◆ ui_session_destroy()

void ui_session_destroy ( ui_session_t * session)

Definition at line 73 of file lib/tui/session.c.

73 {
74 if (!s)
75 return;
76 if (log_get_session_log_buffer() == s->logs)
78 animation_destroy(&s->animation);
79 frame_buffer_destroy(s->frame);
80 frame_buffer_destroy(s->media);
81 if (s->owns_logs)
83 SAFE_FREE(s);
84}
#define SAFE_FREE(ptr)
Definition common.h:377
session_log_buffer_t * log_get_session_log_buffer(void)
Get the currently registered session log buffer.
Definition log.c:2071
void log_clear_session_log_buffer(void)
Unregister the session log buffer.
Definition log.c:2057
void session_log_buffer_destroy(session_log_buffer_t *buf)
Cleanup session log buffer instance.
void animation_destroy(animation_t *a)

References ui_session::animation, animation_destroy(), ui_session::frame, frame_buffer_destroy(), log_clear_session_log_buffer(), log_get_session_log_buffer(), ui_session::logs, ui_session::media, ui_session::owns_logs, SAFE_FREE, and session_log_buffer_destroy().

Referenced by ui_controller_shutdown(), ui_session_create(), and SessionUiBinding::~SessionUiBinding().

◆ ui_session_frame_length()

size_t ui_session_frame_length ( const ui_session_t * session)

Definition at line 165 of file lib/tui/session.c.

165 {
166 size_t length = s ? frame_buffer_get_length(s->frame) : 0;
167 return length ? length - 1 : 0;
168}

References ui_session::frame, and frame_buffer_get_length().

◆ ui_session_help_free()

void ui_session_help_free ( char * text)

Release rendered help with the same allocator that created it.

Definition at line 33 of file session_help.c.

33 {
34 SAFE_FREE(text);
35}

References SAFE_FREE.

Referenced by ui_session_tick().

◆ ui_session_help_render()

char * ui_session_help_render ( terminal_size_t size,
bool has_media,
bool browser,
terminal_size_t * minimum )

Returns owned ANSI text, released with SAFE_FREE.

Definition at line 124 of file session_help.c.

124 {
125 if (!minimum) {
126 SET_ERRNO(ERROR_INVALID_PARAM, "Help minimum geometry output is required");
127 return NULL;
128 }
129 const char *navigation[] = {
130 "Navigation & Control:",
131 "─────────────────────",
132 "? Toggle this help screen TUI",
133 "q / Esc Quit ascii-chat (Shift+Key to panic exit)",
134 browser ? NULL : "v Open from clipboard",
135 browser ? NULL : "Paste Queue dropped/pasted media",
136 browser ? NULL : "< / > Previous/next media (restart)",
137 has_media ? "Space Play/Pause (files only)" : NULL,
138 has_media ? "[ Toggle Media Playback" : NULL,
139 has_media ? (terminal_should_use_utf8(GET_OPTION(force_utf8)) ? "← / → Seek backward/forward 30s"
140 : "Left / Right Seek backward/forward 30s")
141 : NULL,
142 "m / M Mute/Unmute audio",
143 terminal_should_use_utf8(GET_OPTION(force_utf8)) ? "↑ / ↓ Volume up/down (10%)"
144 : "Up / Down Volume up/down (10%)",
145 "c / C Cycle color mode",
146 "f / F Cycle color filter",
147 "x / X Flip webcam horizontally",
148 "y / Y Flip webcam vertically",
149 "w / W Toggle Face Follow",
150 "r / R Cycle render mode",
151 "- FPS counter",
152#if defined(ASCIICHAT_DIAGNOSTIC_UI)
153 browser ? NULL : "` Error stacks diagnostic TUI",
154#endif
155 browser ? NULL : "o TUI to open media from path or url",
156 "] Live log viewer/searcher TUI",
157 "F12 Version update checker TUI",
158 browser ? NULL : "= Running app statistics TUI",
159#ifndef NDEBUG
160 browser ? NULL : "0 C code sync primitives TUI",
161#endif
162 };
163 char settings[TUI_SESSION_HELP_SETTINGS_COUNT][SESSION_HELP_SETTING_BUFFER_SIZE] = {"Current Settings:", ""};
165 format_volume_bar(GET_OPTION(speakers_volume), volume_bar, sizeof(volume_bar));
166 snprintf(settings[2], sizeof(settings[2]), "Audio : %s", status_indicator(GET_OPTION(audio_enabled)));
167 snprintf(settings[3], sizeof(settings[3]), "Volume : %s", volume_bar);
168 snprintf(settings[4], sizeof(settings[4]), "Color : %s", color_mode_to_string(GET_OPTION(color_mode)));
169 snprintf(settings[5], sizeof(settings[5]), "Filter : %s", color_filter_to_string(GET_OPTION(color_filter)));
170 snprintf(settings[6], sizeof(settings[6]), "Render : %s", render_mode_to_string(GET_OPTION(render_mode)));
171 snprintf(settings[7], sizeof(settings[7]), "Flip : rows=%s cols=%s", status_indicator(GET_OPTION(flip_y)),
172 status_indicator(GET_OPTION(flip_x)));
173 snprintf(settings[8], sizeof(settings[8]), "Face Follow : %s", status_indicator(GET_OPTION(face_follow)));
174 int settings_count = 9;
175 snprintf(settings[settings_count++], sizeof(settings[0]), "Animations (number key toggle):");
176 snprintf(settings[settings_count++], sizeof(settings[0]), "-------------------------------");
177 snprintf(settings[settings_count++], sizeof(settings[0]), "(1) Matrix \"Digital Rain\" : %s",
178 status_indicator(GET_OPTION(matrix_rain)));
179 snprintf(settings[settings_count++], sizeof(settings[0]), "(2) Audio Waveform : %s",
180 status_indicator(GET_OPTION(waveform)));
181 snprintf(settings[settings_count++], sizeof(settings[0]), "(3) Audio Frequencies (FFT) : %s",
182 status_indicator(GET_OPTION(fft)));
183 snprintf(settings[settings_count++], sizeof(settings[0]), "(z) Zalgo intensity : %d", GET_OPTION(zalgo));
184 snprintf(settings[settings_count++], sizeof(settings[0]), "(-) FPS Counter : %s",
185 status_indicator(GET_OPTION(fps_counter)));
186 bool server = !browser && (GET_OPTION(detected_mode) == MODE_SERVER || GET_OPTION(detected_mode) == MODE_MCP_SERVER);
187 bool discovery = !browser && GET_OPTION(detected_mode) == MODE_DISCOVERY_SERVICE;
190 size_t count = 0;
191 for (size_t i = 0; i < sizeof(navigation) / sizeof(navigation[0]); ++i) {
192 const char *line = navigation[i];
193 if (!line || i == 1)
194 continue;
195 if (line[0] == '?' || line[0] == ']' || line[0] == '=' || line[0] == '0' || line[0] == '`' || line[0] == 'o' ||
196 !strncmp(line, "F12", 3))
197 continue;
198 if ((server || discovery) && i > 1 && line[0] != '?' && strncmp(line, "Esc", 3) && line[0] != ']' &&
199 line[0] != '=' && line[0] != '0' && line[0] != '`' && strncmp(line, "F12", 3))
200 continue;
201 const char *end = strstr(line, " ");
202 if (end) {
203 size_t length = (size_t)(end - line);
204 if (length >= sizeof(key_storage[0]))
205 length = sizeof(key_storage[0]) - 1;
206 memcpy(key_storage[count], line, length);
207 key_storage[count][length] = '\0';
208 while (*end == ' ')
209 ++end;
210 entries[count] = (ui_help_entry_t){.keys = key_storage[count], .description = end};
211 } else
212 entries[count] = (ui_help_entry_t){.description = line};
213 ++count;
214 }
215 count += tui_shortcut_help(entries + count, 40 - count, server || discovery, browser);
216 if (server || discovery) {
217 settings_count = 4;
218 snprintf(settings[0], sizeof(settings[0]), "%s", discovery ? "Discovery service:" : "Server:");
219 snprintf(settings[1], sizeof(settings[1]), "Port : %d", GET_OPTION(port));
220 snprintf(settings[2], sizeof(settings[2]), "Status screen : %s", status_indicator(GET_OPTION(status_screen)));
221 snprintf(settings[3], sizeof(settings[3]), "Log level : %d", GET_OPTION(log_level));
222 }
223 const char *settings_text[TUI_SESSION_HELP_SETTINGS_COUNT];
224 for (int i = 0; i < settings_count; ++i)
225 settings_text[i] = settings[i];
227 snprintf(footer, sizeof(footer), "Press %s to close", colored_string(LOG_COLOR_WARN, "?"));
228 ui_help_menu_t menu = {.title = discovery ? "ascii-chat Discovery Service Keyboard Shortcuts"
229 : server ? "ascii-chat Server Keyboard Shortcuts"
230 : "ascii-chat Keyboard Shortcuts",
231 .entries = entries,
232 .count = count,
233 .settings = settings_text,
234 .settings_count = (size_t)settings_count,
235 .footer = footer,
236 // Browser sessions draw a four-row animated logo above the popup.
237 .top_margin = browser ? 6 : 0};
238 *minimum = ui_help_menu_measure(&menu);
239 frame_buffer_t *output = frame_buffer_create(size.rows, size.cols);
240 if (!output)
241 return NULL;
242 ui_help_menu_render(output, size, &menu);
243 size_t length = frame_buffer_get_length(output);
244 char *result = SAFE_MALLOC(length + 1, char *);
245 memcpy(result, frame_buffer_get_content(output), length);
246 result[length] = '\0';
247 frame_buffer_destroy(output);
248 return result;
249}
int color_mode
Definition fft.c:25
@ MODE_MCP_SERVER
Model Context Protocol rendering server.
Definition options.h:925
@ MODE_DISCOVERY_SERVICE
Discovery server mode - session management and WebRTC signaling.
Definition options.h:923
@ MODE_SERVER
Server mode - network server options.
Definition options.h:920
const char * color_mode_to_string(terminal_color_mode_t mode)
Convert color mode enum to string.
const char * render_mode_to_string(terminal_render_mode_t mode)
if(!queries||!out||index >=DATABASE_QUERY_COUNT) return false
#define TUI_SESSION_HELP_KEY_STORAGE_COUNT
Definition session_help.c:5
#define SESSION_HELP_ENTRY_CAPACITY
#define TUI_SESSION_HELP_VOLUME_BAR_BUFFER_SIZE
Definition session_help.c:4
#define SESSION_HELP_KEY_BUFFER_SIZE
#define SESSION_HELP_SETTING_BUFFER_SIZE
Definition session_help.c:9
#define TUI_SESSION_HELP_SETTINGS_COUNT
Definition session_help.c:3
size_t tui_shortcut_help(ui_help_entry_t *entries, size_t capacity, bool server, bool browser)
Definition shortcuts.c:39

References color_mode, color_mode_to_string(), colored_string(), ERROR_INVALID_PARAM, frame_buffer_create(), frame_buffer_destroy(), frame_buffer_get_content(), frame_buffer_get_length(), GET_OPTION, LOG_COLOR_WARN, MODE_DISCOVERY_SERVICE, MODE_MCP_SERVER, MODE_SERVER, render_mode_to_string(), SAFE_MALLOC, SESSION_HELP_ENTRY_CAPACITY, SESSION_HELP_KEY_BUFFER_SIZE, SESSION_HELP_SETTING_BUFFER_SIZE, SET_ERRNO, TUI_SESSION_HELP_FOOTER_BUFFER_SIZE, TUI_SESSION_HELP_KEY_STORAGE_COUNT, TUI_SESSION_HELP_SETTINGS_COUNT, TUI_SESSION_HELP_VOLUME_BAR_BUFFER_SIZE, tui_shortcut_help(), ui_help_menu_measure(), and ui_help_menu_render().

Referenced by ui_session_context_help_render(), and ui_session_tick().

◆ ui_session_input()

ui_session_action_t ui_session_input ( ui_session_t * session,
keyboard_key_t key )

Definition at line 129 of file lib/tui/session.c.

129 {
130 if (!s)
131 return UI_ACTION_NONE;
132 if (s->show_logs && ui_session_logs_key_sized(key, s->size)) {
133 s->dirty = true;
134 return UI_ACTION_LOGS;
135 }
136 ui_session_action_t action = ui_session_key(key, &s->saved_volume);
137 if (action == UI_ACTION_HELP) {
138 s->help = !s->help;
139 s->show_logs = false;
140 } else if (action == UI_ACTION_LOGS) {
141 s->show_logs = !s->show_logs;
142 s->help = false;
143 } else if (action == UI_ACTION_CLOSE && s->show_logs) {
144 s->show_logs = false;
146 } else if (action == UI_ACTION_CLOSE && s->help) {
147 s->help = false;
149 }
150 s->dirty |= action != UI_ACTION_NONE;
151 return action;
152}
deferred_action_t action
Definition actions.c:77
ui_session_action_t ui_session_key(keyboard_key_t key, double *saved_volume)

References action, ui_session::dirty, ui_session::help, ui_session::saved_volume, ui_session::show_logs, ui_session::size, UI_ACTION_CLOSE, UI_ACTION_HELP, UI_ACTION_LOGS, UI_ACTION_NONE, and ui_session_key().

Referenced by SessionUiBinding::key().

◆ ui_session_is_covered()

bool ui_session_is_covered ( const ui_session_t * session)

Definition at line 161 of file lib/tui/session.c.

161 {
162 return s && s->covered;
163}

References ui_session::covered.

◆ ui_session_key()

ui_session_action_t ui_session_key ( keyboard_key_t key,
double * saved_volume )

Mutates shared options for settings keys; returns an action for the host.

Definition at line 106 of file session_input.c.

106 {
107 switch ((int)key) {
108 case 'q':
109 return UI_ACTION_QUIT;
110 case 'Q':
112 case KEY_QUESTION:
113 return UI_ACTION_HELP;
114 case '[':
116 case ']':
117 return UI_ACTION_LOGS;
118 case KEY_ESCAPE:
119 return UI_ACTION_CLOSE;
120 case KEY_SHIFT_ESCAPE:
122 case KEY_LEFT:
123 return UI_ACTION_SEEK_BACK;
124 case KEY_RIGHT:
126 case KEY_SPACE:
127 return UI_ACTION_PAUSE;
128 case KEY_BACKTICK:
129 return UI_ACTION_DEBUG;
130 // ===== VOLUME CONTROLS =====
131 case KEY_DOWN: { // Decrease volume 10%
132 double current_volume = GET_OPTION(speakers_volume);
133 double new_volume = clamp_volume(current_volume - 0.1);
134 options_adjust("speakers_volume", key == KEY_DOWN ? -0.1 : 0.1);
135
136 double verify_volume = GET_OPTION(speakers_volume);
137 log_info("Volume DOWN: %.0f%% → %.0f%% (verified: %.0f%%)", current_volume * 100.0, new_volume * 100.0,
138 verify_volume * 100.0);
139 return UI_ACTION_VOLUME;
140 }
141
142 case KEY_UP: { // Increase volume 10%
143 double current_volume = GET_OPTION(speakers_volume);
144 double new_volume = clamp_volume(current_volume + 0.1);
145 options_adjust("speakers_volume", key == KEY_DOWN ? -0.1 : 0.1);
146
147 double verify_volume = GET_OPTION(speakers_volume);
148 log_info("Volume UP: %.0f%% → %.0f%% (verified: %.0f%%)", current_volume * 100.0, new_volume * 100.0,
149 verify_volume * 100.0);
150 return UI_ACTION_SETTINGS;
151 }
152
153 // ===== COLOR MODE CONTROL =====
154 case KEY_C:
155 case 'C': {
156 int current_mode = (int)GET_OPTION(color_mode);
157 int next_mode = next_color_mode(current_mode);
158 options_cycle("color_mode", 4);
159
160 const char *mode_names[] = {"Mono", "16-color", "256-color", "Truecolor"};
161 if (next_mode >= 0 && next_mode <= 3) {
162 log_info("Color mode: %s", mode_names[next_mode]);
163 }
164 return UI_ACTION_SETTINGS;
165 }
166
167 // ===== MUTE CONTROL =====
168 case KEY_M:
169 case 'M': {
170 if (toggle_mute(saved_volume) != ASCIICHAT_OK)
171 log_warn("Could not toggle mute");
172
173 return UI_ACTION_SETTINGS;
174 }
175
176 // ===== RENDER MODE CONTROL =====
177 case KEY_R:
178 case 'R': {
179 int current_mode = (int)GET_OPTION(render_mode);
180 int next_mode = next_render_mode(current_mode);
181 options_cycle("render_mode", 3);
182
183 const char *mode_names[] = {"Foreground", "Background", "Half-block"};
184 if (next_mode >= 0 && next_mode <= 2) {
185 log_info("Render mode: %s", mode_names[next_mode]);
186 }
187 return UI_ACTION_SETTINGS;
188 }
189
190 // ===== COLOR FILTER CONTROL =====
191 case KEY_F:
192 case 'F': {
193 int current_filter = (int)GET_OPTION(color_filter);
194 int next_filter = next_color_filter(current_filter);
195 options_cycle("color_filter", 13);
196
197 if (next_filter >= 0 && next_filter < (int)COLOR_FILTER_COUNT) {
198 log_info("Color filter: %s", COLOR_FILTER_NAMES[next_filter]);
199 }
200 return UI_ACTION_SETTINGS;
201 }
202
203 // ===== HORIZONTAL FLIP CONTROL =====
204 case 'X':
205 case 'x': {
206 log_info("✓ X KEY PRESSED - handling horizontal flip");
207 bool current_flip_x = (bool)GET_OPTION(flip_x);
208 options_toggle("flip_x");
209 log_info("Horizontal flip: %s (was: %s)", !current_flip_x ? "enabled" : "disabled",
210 current_flip_x ? "enabled" : "disabled");
211 return UI_ACTION_SETTINGS;
212 }
213
214 // ===== VERTICAL FLIP CONTROL =====
215 case 'Y':
216 case 'y': {
217 bool current_flip_y = (bool)GET_OPTION(flip_y);
218 options_toggle("flip_y");
219 log_info("Vertical flip: %s", !current_flip_y ? "enabled" : "disabled");
220 return UI_ACTION_SETTINGS;
221 }
222
223 // ===== MATRIX RAIN EFFECT CONTROL =====
224 case KEY_1: {
225 bool current_matrix = (bool)GET_OPTION(matrix_rain);
226 if (options_toggle("matrix_rain") != ASCIICHAT_OK)
227 return UI_ACTION_SETTINGS;
228 log_info("Matrix rain effect: %s", !current_matrix ? "enabled" : "disabled");
229 return UI_ACTION_SETTINGS;
230 }
231
232 case KEY_2: {
233 if (!GET_OPTION(audio_enabled)) {
234 log_info("Audio waveform requires audio to be enabled");
235 return UI_ACTION_SETTINGS;
236 }
237 bool enabled = !GET_OPTION(waveform);
238 if (options_toggle("waveform") != ASCIICHAT_OK)
239 return UI_ACTION_SETTINGS;
240 log_info("Audio waveform: %s", enabled ? "enabled" : "disabled");
241 return UI_ACTION_SETTINGS;
242 }
243
244 case KEY_3: {
245 if (!GET_OPTION(audio_enabled)) {
246 log_info("Audio frequency display requires audio to be enabled");
247 return UI_ACTION_SETTINGS;
248 }
249 bool enabled = !GET_OPTION(fft);
251 log_error("Unable to initialize FFTW frequency display");
252 return UI_ACTION_SETTINGS;
253 }
254 if (options_toggle("fft") != ASCIICHAT_OK)
255 return UI_ACTION_SETTINGS;
256 log_info("Audio frequency display: %s", enabled ? "enabled" : "disabled");
257 return UI_ACTION_SETTINGS;
258 }
259
260 case 'w':
261 case 'W': {
262 if (options_toggle("face_follow") == ASCIICHAT_OK)
263 log_info("Face follow: %s", GET_OPTION(face_follow) ? "enabled" : "disabled");
264 return UI_ACTION_SETTINGS;
265 }
266
267 case 'z':
268 case 'Z': {
269 if (options_set_int("zalgo", GET_OPTION(zalgo) ? 0 : 8) == ASCIICHAT_OK)
270 log_info("Zalgo intensity: %d", GET_OPTION(zalgo));
271 return UI_ACTION_SETTINGS;
272 }
273
274 // ===== FPS COUNTER TOGGLE =====
275 case KEY_MINUS: {
276 bool current = (bool)GET_OPTION(fps_counter);
277 options_toggle("fps_counter");
278 log_info("FPS counter: %s", !current ? "enabled" : "disabled");
279 return UI_ACTION_SETTINGS;
280 }
281
282 default:
283 return UI_ACTION_NONE;
284 }
285}
asciichat_error_t audio_visualization_fft_init(void)
Definition fft.c:61
bool enabled
Is filtering active?
Definition grep.c:62
@ ASCIICHAT_OK
Definition error_codes.h:46
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
asciichat_error_t options_set_int(const char *name, int value)
Check if an option was explicitly set via command-line.
Definition rcu.c:894
@ KEY_SPACE
Space bar.
Definition keyboard.h:56
@ KEY_UP
Up arrow key.
Definition keyboard.h:57
@ KEY_M
'm' key - toggle mute
Definition keyboard.h:81
@ KEY_SHIFT_ESCAPE
Shift+Escape (immediate exit).
Definition keyboard.h:73
@ KEY_2
'2' key - toggle audio waveform
Definition keyboard.h:77
@ KEY_BACKTICK
'`' key - print lock state (debug builds)
Definition keyboard.h:84
@ KEY_1
'1' key - toggle matrix rain effect
Definition keyboard.h:76
@ KEY_ESCAPE
Escape key (ESC).
Definition keyboard.h:55
@ KEY_F
'f' key - flip webcam
Definition keyboard.h:82
@ KEY_MINUS
'-' key - toggle FPS counter
Definition keyboard.h:74
@ KEY_LEFT
Left arrow key.
Definition keyboard.h:59
@ KEY_RIGHT
Right arrow key.
Definition keyboard.h:60
@ KEY_C
'c' key - cycle color modes
Definition keyboard.h:79
@ KEY_R
'r' key - cycle render modes
Definition keyboard.h:80
@ KEY_DOWN
Down arrow key.
Definition keyboard.h:58
@ KEY_QUESTION
'?' key - show help screen
Definition keyboard.h:83
@ KEY_3
'3' key - toggle audio frequency display
Definition keyboard.h:78
asciichat_error_t options_adjust(const char *name, double amount)
Definition rcu.c:914
asciichat_error_t options_toggle(const char *name)
Definition rcu.c:911
asciichat_error_t options_cycle(const char *name, int count)
Definition rcu.c:918

References ASCIICHAT_OK, audio_visualization_fft_init(), color_mode, enabled, GET_OPTION, KEY_1, KEY_2, KEY_3, KEY_BACKTICK, KEY_C, KEY_DOWN, KEY_ESCAPE, KEY_F, KEY_LEFT, KEY_M, KEY_MINUS, KEY_QUESTION, KEY_R, KEY_RIGHT, KEY_SHIFT_ESCAPE, KEY_SPACE, KEY_UP, log_error, log_info, log_warn, options_adjust(), options_cycle(), options_set_int(), options_toggle(), UI_ACTION_CLOSE, UI_ACTION_DEBUG, UI_ACTION_FORCE_QUIT, UI_ACTION_HELP, UI_ACTION_LOGS, UI_ACTION_NONE, UI_ACTION_PAUSE, UI_ACTION_QUIT, UI_ACTION_SEEK_BACK, UI_ACTION_SEEK_FORWARD, UI_ACTION_SETTINGS, UI_ACTION_TOGGLE_MEDIA, and UI_ACTION_VOLUME.

Referenced by ui_session_input().

◆ ui_session_loading()

void ui_session_loading ( ui_session_t * session,
bool loading,
const char * message )

Definition at line 97 of file lib/tui/session.c.

97 {
98 if (!s)
99 return;
100 if (loading != s->loading) {
101 s->loading = loading;
102 animation_reset(&s->animation);
103 s->dirty = true;
104 }
105 if (message && strcmp(message, s->splash.connection_target)) {
106 SAFE_STRNCPY(s->splash.connection_target, message, sizeof(s->splash.connection_target));
107 s->dirty = true;
108 }
109}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
void animation_reset(animation_t *a)

References ui_session::animation, animation_reset(), ui_splash_view_t::connection_target, ui_session::dirty, ui_session::loading, SAFE_STRNCPY, and ui_session::splash.

Referenced by SessionUiBinding::loading().

◆ ui_session_log()

void ui_session_log ( ui_session_t * session,
const char * message )

Definition at line 111 of file lib/tui/session.c.

111 {
112 if (s && message) {
113 session_log_buffer_append(s->logs, message);
114 s->dirty = true;
115 }
116}
void session_log_buffer_append(session_log_buffer_t *buf, const char *message)
Append a log message to the buffer.

References ui_session::dirty, ui_session::logs, and session_log_buffer_append().

Referenced by SessionUiBinding::log().

◆ ui_session_logs_key()

bool ui_session_logs_key ( keyboard_key_t key)

Existing server log-search controls; true when consumed.

Definition at line 296 of file lib/tui/session.c.

296 {
297 return ui_session_logs_key_sized(key, ui_controller_size());
298}
terminal_size_t ui_controller_size(void)

References ui_controller_size().

◆ ui_session_logs_render()

void ui_session_logs_render ( frame_buffer_t * output,
terminal_size_t size,
ui_session_t * session )

Shared live log view, used by the native adapter and browser compositor.

Definition at line 244 of file lib/tui/session.c.

244 {
246 size_t offset = terminal_screen_logs_offset();
247 char offset_text[TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE];
248 snprintf(offset_text, sizeof(offset_text), "%zu", offset);
249 const char *colored_offset = colored_string(LOG_COLOR_FATAL, offset_text);
250 snprintf(detail, sizeof(detail), "%s | %s rows from tail", ui_status_log_controls(), colored_offset);
251 ui_status_t status = {.mode_name = "", .start_time = s->started, .detail = detail};
252 terminal_screen_config_t config = {
253 .fixed_header_lines = 4, .render_header = ui_status_render_header, .user_data = &status, .show_logs = true};
254 terminal_screen_compose(output, size, &config, s->logs);
255}
@ LOG_COLOR_FATAL
Definition log/log.h:153
#define TUI_SESSION_DETAIL_BUFFER_SIZE
#define TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE
void ui_status_render_header(frame_buffer_t *buf, terminal_size_t term_size, void *user_data)
void terminal_screen_compose(frame_buffer_t *output, terminal_size_t size, const terminal_screen_config_t *config, session_log_buffer_t *logs)
const char * ui_status_log_controls(void)
Definition status.c:34
Configuration for terminal screen rendering.
Status information for server/discovery service modes.
Definition status.h:38
size_t terminal_screen_logs_offset(void)

References colored_string(), LOG_COLOR_FATAL, ui_session::logs, ui_session::started, terminal_screen_compose(), terminal_screen_logs_offset(), TUI_SESSION_DETAIL_BUFFER_SIZE, TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE, ui_status_log_controls(), and ui_status_render_header().

◆ ui_session_media()

asciichat_error_t ui_session_media ( ui_session_t * session,
const char * data,
size_t length )

Definition at line 118 of file lib/tui/session.c.

118 {
119 if (!s || !data || length > UI_CONTROLLER_MAX_FRAME_BYTES)
120 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid session media frame");
121 frame_buffer_reset(s->media);
122 frame_buffer_append(s->media, data, length);
123 s->dirty = true;
124 return ASCIICHAT_OK;
125}
void frame_buffer_append(frame_buffer_t *buf, const char *str, size_t len)
Append raw bytes to the buffer.
#define UI_CONTROLLER_MAX_FRAME_BYTES

References ASCIICHAT_OK, ui_session::dirty, ERROR_INVALID_PARAM, frame_buffer_append(), frame_buffer_reset(), ui_session::media, SET_ERRNO, and UI_CONTROLLER_MAX_FRAME_BYTES.

Referenced by SessionUiBinding::media().

◆ ui_session_next_frame_ns()

uint64_t ui_session_next_frame_ns ( const ui_session_t * session)

Next visible animation deadline, or UINT64_MAX while animation is paused/hidden.

Definition at line 170 of file lib/tui/session.c.

170 {
171 return s && s->animation.started ? s->splash.animation.next_frame_ns : UINT64_MAX;
172}

References ui_session::animation, ui_splash_view_t::animation, animation_sample_t::next_frame_ns, ui_session::splash, and animation_t::started.

◆ ui_session_redraw()

void ui_session_redraw ( ui_session_t * session)

Definition at line 370 of file lib/tui/session.c.

370 {
371 if (s)
372 s->dirty = true;
373}

References ui_session::dirty.

Referenced by SessionUiBinding::redraw(), and ui_controller_redraw().

◆ ui_session_render()

const char * ui_session_render ( ui_session_t * session,
const ui_session_view_t * view,
uint64_t now_ns )

Present a host view through the same compositor used by ui_session_tick(). A screen of -1 hides presentation. NULL means no redraw is required.

Definition at line 174 of file lib/tui/session.c.

174 {
175 if (!s || !view)
176 return NULL;
177 bool changed = s->active != view->screen;
178 s->active = view->screen;
179 bool covered = view->screen >= 0 && ui_too_small(s->size, view->minimum);
180 bool transition = changed || covered != s->covered || s->size.cols != s->presented_size.cols ||
181 s->size.rows != s->presented_size.rows || view->minimum.cols != s->minimum.cols ||
182 view->minimum.rows != s->minimum.rows;
183 s->covered = covered;
184 bool visible =
185 (view->screen == UI_SCREEN_SPLASH || view->screen == UI_SCREEN_HELP || view->screen == UI_SCREEN_MDNS) &&
186 !covered;
187 if (visible != s->animation.visible) {
188 // Account for the elapsed interval under the old visibility before changing
189 // it, so resuming after an idle modal does not advance a paused animation.
190 if (animation_update(&s->animation, now_ns, &s->splash.animation) != ASCIICHAT_OK)
191 return NULL;
192 animation_set_visible(&s->animation, visible);
193 }
194 if (animation_update(&s->animation, now_ns, &s->splash.animation) != ASCIICHAT_OK)
195 return NULL;
196 if (view->screen < 0 || !view->draw)
197 return NULL;
198 bool animated = visible && s->splash.animation.changed;
199 bool refresh = view->refresh_ns && now_ns - s->last_render_ns >= view->refresh_ns;
200 if (covered ? !(transition || s->dirty) : !(transition || s->dirty || view->dirty || animated || refresh))
201 return NULL;
202 s->dirty = false;
203 s->presented_size = s->size;
204 s->minimum = view->minimum;
205 s->last_render_ns = now_ns;
206 frame_buffer_reset(s->frame);
207 if (transition || view->clear) {
208 frame_buffer_append(s->frame, "\033[0m", 4);
210 }
211 if (covered)
212 ui_too_small_render(s->frame, s->size, view->minimum);
213 else {
214 if (view->screen == UI_SCREEN_HELP) {
215 int top = (s->size.rows - view->minimum.rows) / 2;
216 terminal_color_mode_t mode = GET_OPTION(color_mode);
217 bool colors = mode != TERM_COLOR_NONE && GET_OPTION(color) != COLOR_SETTING_FALSE && !GET_OPTION(strip_ansi) &&
218 (mode != TERM_COLOR_AUTO ||
219 detect_terminal_capabilities(options_terminal_settings()).color_level != TERM_COLOR_NONE);
220 frame_buffer_printf(s->frame, "\033[%d;1H", top + 2);
221 invitation_render_logo(s->frame, s->size.cols, (int)(s->splash.animation.seconds * 60), colors, false);
222 }
223 view->draw(s->frame, s->size, &s->splash.animation, view->context);
224 }
225 frame_buffer_append(s->frame, "\0", 1);
226 return frame_buffer_get_content(s->frame);
227}
unsigned char colors[(512 *256 *2) *3]
Definition fft.c:22
void frame_buffer_printf(frame_buffer_t *buf, const char *fmt,...)
Printf-style append to the buffer.
void frame_buffer_clear_screen(frame_buffer_t *buf)
Append clear screen and home escape codes (\033[2J\033[H).
#define options_terminal_settings()
Definition options.h:1296
@ COLOR_SETTING_FALSE
Force colors OFF: disable all colors and logging colors.
Definition options.h:249
void invitation_render_logo(frame_buffer_t *buf, int cols, int frame, bool colors, bool compact)
Definition invitation.c:34
void ui_too_small_render(frame_buffer_t *buffer, terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:38
bool ui_too_small(terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:10
@ UI_SCREEN_SPLASH
@ UI_SCREEN_HELP
asciichat_error_t animation_update(animation_t *a, uint64_t now, animation_sample_t *out)
void animation_set_visible(animation_t *a, bool visible)

References ui_session::active, ui_session::animation, ui_splash_view_t::animation, animation_set_visible(), animation_update(), ASCIICHAT_OK, animation_sample_t::changed, ui_session_view_t::clear, color_mode, COLOR_SETTING_FALSE, colors, ui_session_view_t::context, ui_session::covered, ui_session::dirty, ui_session_view_t::dirty, ui_session_view_t::draw, ui_session::frame, frame_buffer_append(), frame_buffer_clear_screen(), frame_buffer_get_content(), frame_buffer_printf(), frame_buffer_reset(), GET_OPTION, invitation_render_logo(), ui_session::last_render_ns, ui_session::minimum, ui_session_view_t::minimum, options_terminal_settings, ui_session::presented_size, ui_session_view_t::refresh_ns, ui_session_view_t::screen, animation_sample_t::seconds, ui_session::size, ui_session::splash, UI_SCREEN_HELP, UI_SCREEN_MDNS, UI_SCREEN_SPLASH, ui_too_small(), ui_too_small_render(), and animation_t::visible.

Referenced by ui_session_tick().

◆ ui_session_resize()

void ui_session_resize ( ui_session_t * session,
int cols,
int rows )

Definition at line 86 of file lib/tui/session.c.

86 {
87 if (!s || cols < 1 || rows < 1 || cols > 4096 || rows > 4096) {
88 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid TUI session or terminal dimensions");
89 return;
90 }
91 if (cols != s->size.cols || rows != s->size.rows) {
92 s->size = (terminal_size_t){.cols = cols, .rows = rows};
93 s->dirty = true;
94 }
95}

References ui_session::dirty, ERROR_INVALID_PARAM, SET_ERRNO, and ui_session::size.

Referenced by SessionUiBinding::resize().

◆ ui_session_select_screen()

int ui_session_select_screen ( uint32_t visible_screens)

Highest visible screen from the common priority order, or -1.

Definition at line 154 of file lib/tui/session.c.

154 {
155 for (int screen = UI_SCREEN_COUNT - 1; screen >= 0; --screen)
156 if (visible_screens & (1u << screen))
157 return screen;
158 return -1;
159}
@ UI_SCREEN_COUNT

References UI_SCREEN_COUNT.

Referenced by ui_session_tick().

◆ ui_session_size()

terminal_size_t ui_session_size ( const ui_session_t * session)

Definition at line 366 of file lib/tui/session.c.

366 {
367 return s ? s->size : (terminal_size_t){.cols = 80, .rows = 24};
368}

References ui_session::size.

Referenced by ui_controller_size().

◆ ui_session_splash_render()

void ui_session_splash_render ( frame_buffer_t * buf,
terminal_size_t size,
void * view )

Definition at line 19 of file session_splash.c.

19 {
20 const ui_splash_view_t *ctx = (const ui_splash_view_t *)user_data;
21 if (!ctx) {
22 return;
23 }
24 bool unicode = terminal_should_use_utf8(GET_OPTION(force_utf8));
25
26 if (ctx->discovery.enabled) {
28 (int)(ctx->animation.seconds * 60), ctx->use_colors);
29 return;
30 }
31
33 snprintf(tagline_with_version, sizeof(tagline_with_version), "Video chat in your terminal + %s",
34 ASCII_CHAT_VERSION_STRING);
35 const char *tagline = tagline_with_version;
36 frame_buffer_render_divider(buf, term_size.cols - 1, unicode, ctx->use_colors);
37 invitation_render_logo(buf, term_size.cols - 1, (int)(ctx->animation.seconds * 60), ctx->use_colors, false);
38
39 // Line 6: Tagline (centered, truncated if too long)
41 int tagline_len = (int)strlen(tagline);
42 int tagline_pad = (term_size.cols - tagline_len) / 2;
43 if (tagline_pad < 0) {
44 tagline_pad = 0;
45 }
46
47 int tpos = 0;
48 for (int j = 0; j < tagline_pad && tpos < (int)sizeof(plain_tagline) - 1; j++) {
49 plain_tagline[tpos++] = ' ';
50 }
51 snprintf(plain_tagline + tpos, sizeof(plain_tagline) - tpos, "%s", tagline);
52
53 // Check visible width and truncate if needed
54 int tagline_visible_width = display_width(plain_tagline);
55 if (tagline_visible_width < 0) {
56 tagline_visible_width = (int)strlen(plain_tagline);
57 }
58 if (term_size.cols > 0 && tagline_visible_width >= term_size.cols) {
59 plain_tagline[term_size.cols - 1] = '\0';
60 }
61
62 frame_buffer_printf(buf, "%s\n", plain_tagline);
63
64 // Line 7: Update notification (if available)
65 if (ctx->update_notification[0] != '\0') {
67 int update_len = (int)strlen(ctx->update_notification);
68 int update_pad = (term_size.cols - update_len) / 2;
69 if (update_pad < 0) {
70 update_pad = 0;
71 }
72
73 int upos = 0;
74 for (int j = 0; j < update_pad && upos < (int)sizeof(plain_update) - 1; j++) {
75 plain_update[upos++] = ' ';
76 }
77 snprintf(plain_update + upos, sizeof(plain_update) - upos, "%s", ctx->update_notification);
78
79 // Check visible width and truncate if needed
80 int update_visible_width = display_width(plain_update);
81 if (update_visible_width < 0) {
82 update_visible_width = (int)strlen(plain_update);
83 }
84 if (term_size.cols > 0 && update_visible_width >= term_size.cols) {
85 plain_update[term_size.cols - 1] = '\0';
86 }
87
88 // Print in yellow/warning color
89 frame_buffer_printf(buf, "%s\n", colored_string(LOG_COLOR_WARN, plain_update));
90 }
91
92 // Line 8 (or 7 if no update): Connection target (centered, truncated if too long)
93 const char *connection_target = ctx->connection_target;
94
96 int connection_len = (int)strlen(connection_target);
97 int connection_pad = (term_size.cols - connection_len) / 2;
98 if (connection_pad < 0) {
99 connection_pad = 0;
100 }
101
102 int cpos = 0;
103 for (int j = 0; j < connection_pad && cpos < (int)sizeof(plain_connection) - 1; j++) {
104 plain_connection[cpos++] = ' ';
105 }
106 snprintf(plain_connection + cpos, sizeof(plain_connection) - cpos, "%s", connection_target);
107
108 // Check visible width and truncate if needed
109 int connection_visible_width = display_width(plain_connection);
110 if (connection_visible_width < 0) {
111 connection_visible_width = (int)strlen(plain_connection);
112 }
113 if (term_size.cols > 0 && connection_visible_width >= term_size.cols) {
114 plain_connection[term_size.cols - 1] = '\0';
115 }
116
117 frame_buffer_printf(buf, "%s\n", plain_connection);
118
120 static const char spin[] = "|/-\\";
121 const char *text = "Checking for updates...";
122 int pad = term_size.cols - (int)strlen(text) - 3;
123 if (pad < 0)
124 pad = 0;
125 frame_buffer_printf(buf, "%*s%c %s\n", pad, "", spin[((int)(ctx->animation.seconds * 8)) % 4], text);
126 }
127
128 // Bottom border
129 frame_buffer_render_divider(buf, term_size.cols - 1, unicode, ctx->use_colors);
130}
void frame_buffer_render_divider(frame_buffer_t *buf, int width, bool use_utf8, bool use_colors)
bool update_banner_is_checking(void)
int display_width(const char *text)
Calculate the visible display width of text with ANSI escape codes.
void invitation_render(frame_buffer_t *buf, terminal_size_t size, const char *session, bool joining, int frame, bool colors)
Definition invitation.c:58
#define TUI_SESSION_SPLASH_PLAIN_CONNECTION_BUFFER_SIZE
#define TUI_SESSION_SPLASH_PLAIN_TAGLINE_BUFFER_SIZE
#define TUI_SESSION_SPLASH_PLAIN_UPDATE_BUFFER_SIZE
#define TUI_SESSION_SPLASH_TAGLINE_WITH_VERSION_BUFFER_SIZE

References ui_splash_view_t::animation, colored_string(), ui_splash_view_t::connection_target, ui_splash_view_t::discovery, display_width(), ui_discovery_view_t::enabled, frame_buffer_printf(), frame_buffer_render_divider(), GET_OPTION, invitation_render(), invitation_render_logo(), ui_discovery_view_t::joining, LOG_COLOR_WARN, animation_sample_t::seconds, ui_discovery_view_t::session_string, TUI_SESSION_SPLASH_PLAIN_CONNECTION_BUFFER_SIZE, TUI_SESSION_SPLASH_PLAIN_TAGLINE_BUFFER_SIZE, TUI_SESSION_SPLASH_PLAIN_UPDATE_BUFFER_SIZE, TUI_SESSION_SPLASH_TAGLINE_WITH_VERSION_BUFFER_SIZE, update_banner_is_checking(), ui_splash_view_t::update_notification, and ui_splash_view_t::use_colors.

◆ ui_session_tick()

const char * ui_session_tick ( ui_session_t * session,
uint64_t now_ns )

No sleeps or I/O. Returned frame remains valid until the next call. NULL means unchanged.

Definition at line 319 of file lib/tui/session.c.

319 {
320 if (!s)
321 return NULL;
322 if (!s->dirty && !s->show_logs && !s->help && !s->loading && s->active == UI_SCREEN_MEDIA)
323 return NULL;
324 uint32_t visible = 1u << UI_SCREEN_MEDIA;
325 if (s->loading)
326 visible |= 1u << UI_SCREEN_SPLASH;
327 if (s->show_logs)
328 visible |= 1u << UI_SCREEN_LOGS;
329 if (s->help)
330 visible |= 1u << UI_SCREEN_HELP;
331 ui_session_view_t view = {
332 .screen = ui_session_select_screen(visible), .minimum = {1, 1}, .clear = !s->help, .context = s};
333 char *help = NULL;
334 if (view.screen == UI_SCREEN_HELP) {
335 help = ui_session_help_render(s->size, true, true, &view.minimum);
336 if (!help)
337 return NULL;
338 view.draw = draw_help;
339 view.context = help;
340 } else if (view.screen == UI_SCREEN_LOGS) {
341 view.minimum = (terminal_size_t){.cols = 40, .rows = 6};
342 view.refresh_ns = 100000000;
343 view.draw = draw_logs;
344 } else if (view.screen == UI_SCREEN_SPLASH) {
345 view.minimum = (terminal_size_t){.cols = 52, .rows = 10};
346 view.draw = draw_splash;
347 } else {
348 view.draw = draw_media;
349 if (s->dirty && frame_buffer_get_length(s->media))
350 s->presentation_times[s->presentation_index++ % 120] = now_ns;
351 }
352 const char *frame = ui_session_render(s, &view, now_ns);
354 return frame;
355}
unsigned int uint32_t
Definition common.h:62
int ui_session_select_screen(uint32_t visible_screens)
const char * ui_session_render(ui_session_t *s, const ui_session_view_t *view, uint64_t now_ns)
void ui_session_help_free(char *text)
@ UI_SCREEN_LOGS
@ UI_SCREEN_MEDIA

References ui_session::active, ui_session_view_t::context, ui_session::dirty, ui_session_view_t::draw, frame_buffer_get_length(), ui_session::help, ui_session::loading, ui_session::media, ui_session_view_t::minimum, ui_session::presentation_index, ui_session::presentation_times, ui_session_view_t::refresh_ns, ui_session_view_t::screen, ui_session::show_logs, ui_session::size, UI_SCREEN_HELP, UI_SCREEN_LOGS, UI_SCREEN_MEDIA, UI_SCREEN_SPLASH, ui_session_help_free(), ui_session_help_render(), ui_session_render(), and ui_session_select_screen().

Referenced by SessionUiBinding::tick().