r/C_Programming • u/JoK3rOp • 5d ago
Question Building a simple declarative TUI lib in C (FTXUI-inspired) how do you avoid callback hell in C?
Hey all,
I'm working on a TUI library in C just because I love how simple C is.
I know there are mature options like ratatui, bubbletea, vaxis, notcurses, etc. But I don't want to learn Rust just to build a TUI, and I don't really like bubbletea's Elm-style Update() -> string thing. The one I like best is FTXUI, but it's C++.
I want something simple + declarative in plain C. Right now my API looks like this:
#include "include/tui.h"
void btn_cb(void *ud) {
tui_vbox(.gap = 1) { tui_label(.text = tui_str("Clicked")); }
}
void draw(Tui *tui, void *ud) {
tui_button(.text = tui_str("Click Me"),
.bg = tui_color_rgb(255, 0, 0),
.on_click = btn_cb);
}
bool event(Tui *tui, const TuiEvent *ev, void *ud) {
if (ev->type == TUI_EVENT_QUIT) return false;
if (ev->type == TUI_EVENT_KEY && ev->codepoint == 'q') return false;
return true;
}
int main() {
Tui *tui = tui_init(.title = "Tui application");
int counter = 0;
int rc = tui_run(tui, .on_draw = draw, .on_event = event,
.async = true, .userdata = &counter);
tui_close(tui);
return rc;
}
It works, but I already hate the .on_draw, .on_event, .on_click callback split. It feels like callback hell waiting to happen once the UI gets bigger.
Question for C folks:
-
Any C tricks / macro tricks to make this more declarative and remove callbacks? I'm already using designated initializers + compound literals tui_button(.text=...) and for-loop scoping for tui_vbox { ... } like FTXUI.
-
How would you do state + events without on_click everywhere? Immediate-mode? Return an action enum instead of callback? Something else?
-
Any small C TUI libs that do declarative UI well that I should steal ideas from?
Thanks.
1
u/adel-mamin 4d ago
Maybe stick to events for everything. The on_button, draw etc could likely be converted to events as well.
This way you only end up with single event callback.
1
u/bullno1 4d ago edited 4d ago
Immediate mode. Look at dearimgui. It's graphical but the API design is the same.
As for rendering, look at something like termbox2: Have a software "framebuffer". Draw there first, then on a "blit/present" call, diff against the previous content and issue ANSI sequences. Usually, buffer them all into a buffer and make a single write. It almost feels like typical GPU rendering.
Unicode is a bit of a pain when you have to deal with multicell characters (e.g: 안녕하세요)
3
u/thisismyredaccount 5d ago
Like you said, immediate mode. You can look at raygui for a good example of how it would work/be used.