ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
popup.c
Go to the documentation of this file.
1
2/* Storage capacities in elements; text buffers include the terminating NUL. */
3#define UI_POPUP_RENDERED_BUFFER_SIZE 1024
4
10#include <string.h>
11
12asciichat_error_t ui_popup_rule(frame_buffer_t *out, int width, ui_popup_edge_t edge, bool double_border, bool unicode,
13 log_color_t color) {
14 if (!out || width < 2 || edge < UI_POPUP_TOP || edge > UI_POPUP_RULE)
15 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid popup rule output, width or edge");
16 static const char *single[][2] = {{"┌", "┐"}, {"├", "┤"}, {"└", "┘"}, {"", ""}};
17 static const char *dual[][2] = {{"╔", "╗"}, {"╠", "╣"}, {"╚", "╝"}, {"", ""}};
18 const char *left = edge == UI_POPUP_RULE ? "" : !unicode ? "+" : double_border ? dual[edge][0] : single[edge][0];
19 const char *right = edge == UI_POPUP_RULE ? "" : !unicode ? "+" : double_border ? dual[edge][1] : single[edge][1];
20 const char *horizontal = !unicode ? "-" : double_border ? "═" : "─";
21 frame_buffer_printf(out, "%s", colored_string(color, left));
22 for (int i = 0; i < width - (edge == UI_POPUP_RULE ? 0 : 2); ++i)
23 frame_buffer_printf(out, "%s", colored_string(color, horizontal));
24 frame_buffer_printf(out, "%s", colored_string(color, right));
25 return ASCIICHAT_OK;
26}
27
29 if (!out || row < 1 || col < 1 || width < 2 || height < 2)
30 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid popup frame output or rectangle");
31 frame_buffer_printf(out, "\033[%d;%dH", row, col);
32 ui_popup_rule(out, width, UI_POPUP_TOP, false, terminal_should_use_utf8(GET_OPTION(force_utf8)), color);
33 const char *vertical = terminal_should_use_utf8(GET_OPTION(force_utf8)) ? "│" : "|";
34 for (int i = 1; i < height - 1; ++i)
35 frame_buffer_printf(out, "\033[%d;%dH%s%*s%s", row + i, col, colored_string(color, vertical), width - 2, "",
36 colored_string(color, vertical));
37 frame_buffer_printf(out, "\033[%d;%dH", row + height - 1, col);
38 return ui_popup_rule(out, width, UI_POPUP_BOTTOM, false, terminal_should_use_utf8(GET_OPTION(force_utf8)), color);
39}
40
42 const char *title) {
43 if (!title || width < 5)
44 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid popup title or width");
45 asciichat_error_t result = ui_popup_frame(out, row, col, width, height, color);
46 if (result != ASCIICHAT_OK)
47 return result;
48 char rendered[UI_POPUP_RENDERED_BUFFER_SIZE];
49 truncate_with_ellipsis(title, rendered, sizeof(rendered), width - 4);
50 int title_width = display_width(rendered);
51 frame_buffer_printf(out, "\033[%d;%dH %s ", row, col + (width - title_width - 2) / 2,
53 return ASCIICHAT_OK;
54}
55
56bool ui_popup_render(frame_buffer_t *output, terminal_size_t size, const ui_popup_t *box) {
57 if (!output || !box || !box->title || (box->line_count && !box->lines) || box->top_margin < 0) {
58 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid popup output, content or margins");
59 return false;
60 }
61 if (size.cols < 8 || size.rows < 5)
62 return false;
63 int content_width = display_width(box->title);
64 for (size_t i = 0; i < box->line_count; ++i) {
65 int width = display_width(box->lines[i]);
66 if (width > content_width)
67 content_width = width;
68 }
69 if (box->footer && display_width(box->footer) > content_width)
70 content_width = display_width(box->footer);
71 int width = content_width + 4;
72 if (width < box->minimum_width)
73 width = box->minimum_width;
74 if (width > size.cols - 2)
75 width = size.cols - 2;
76 int height = (int)box->line_count + (box->footer ? 5 : 4);
77 if (height > size.rows - 2 - box->top_margin)
78 return false;
79 int left = (size.cols - width) / 2 + 1;
80 int top = box->top_margin + (size.rows - box->top_margin - height) / 2 + 1;
81 if (ui_popup_frame(output, top, left, width, height, LOG_COLOR_RESET) != ASCIICHAT_OK)
82 return false;
83 char rendered[UI_POPUP_RENDERED_BUFFER_SIZE];
84 truncate_with_ellipsis(box->title, rendered, sizeof(rendered), width - 4);
85 const char *colored_title = colored_string(LOG_COLOR_RESET, rendered);
86 frame_buffer_printf(output, "\033[%d;%dH\033[1m%s\033[0m", top + 1, left + 2, colored_title);
87 for (size_t i = 0; i < box->line_count; ++i) {
88 truncate_with_ellipsis(box->lines[i], rendered, sizeof(rendered), width - 4);
89 frame_buffer_printf(output, "\033[%d;%dH%s", top + 2 + (int)i, left + 2, rendered);
90 }
91 if (box->footer) {
92 truncate_with_ellipsis(box->footer, rendered, sizeof(rendered), width - 4);
93 frame_buffer_printf(output, "\033[%d;%dH\033[2m%s\033[0m", top + height - 2, left + 2, rendered);
94 }
95 return true;
96}
#define SET_ERRNO(code,...)
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
void frame_buffer_printf(frame_buffer_t *buf, const char *fmt,...)
Printf-style append to the buffer.
struct frame_buffer frame_buffer_t
Opaque frame buffer handle.
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
log_color_t
Color enum for logging - indexes into color arrays.
Definition log/log.h:147
@ LOG_COLOR_RESET
Definition log/log.h:155
#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
int display_width(const char *text)
Calculate the visible display width of text with ANSI escape codes.
void truncate_with_ellipsis(const char *input, char *output, size_t output_size, int max_width)
Truncate a string to a maximum display width, with ellipsis.
Definition string.c:370
🖥️ Display Width and Terminal Centering Utilities
📝 Logging API with multiple log levels and terminal output control
⚙️ Unified options parsing system for ascii-chat with builder pattern and lock-free access
asciichat_error_t ui_popup_frame(frame_buffer_t *out, int row, int col, int width, int height, log_color_t color)
Definition popup.c:28
asciichat_error_t ui_popup_rule(frame_buffer_t *out, int width, ui_popup_edge_t edge, bool double_border, bool unicode, log_color_t color)
Definition popup.c:12
bool ui_popup_render(frame_buffer_t *output, terminal_size_t size, const ui_popup_t *box)
Definition popup.c:56
#define UI_POPUP_RENDERED_BUFFER_SIZE
Definition popup.c:3
asciichat_error_t ui_popup_frame_titled(frame_buffer_t *out, int row, int col, int width, int height, log_color_t color, const char *title)
Definition popup.c:41
ui_popup_edge_t
Definition popup.h:9
@ UI_POPUP_BOTTOM
Definition popup.h:9
@ UI_POPUP_RULE
Definition popup.h:9
@ UI_POPUP_TOP
Definition popup.h:9
static bool size_t gotel_query_t * out
Definition queries.h:8
🔤 String Manipulation and Shell Escaping Utilities
When code needs to work with ui popup, it keeps title, lines, line_count, footer here instead of scat...
Definition popup.h:23
int top_margin
Definition popup.h:29
const char *const * lines
Definition popup.h:25
const char * title
Definition popup.h:24
int minimum_width
Definition popup.h:28
const char * footer
Definition popup.h:27
size_t line_count
Definition popup.h:26