6 static rtk_draw_ops gfx;
8 static void calc_widget_rect(rtk_widget *w, rtk_rect *rect);
9 static void draw_window(rtk_widget *w);
10 static void draw_button(rtk_widget *w);
11 static void draw_checkbox(rtk_widget *w);
12 static void draw_separator(rtk_widget *w);
14 void rtk_setup(rtk_draw_ops *drawop)
19 rtk_widget *rtk_create_widget(void)
23 if(!(w = calloc(1, sizeof *w))) {
26 w->any.flags = VISIBLE | ENABLED | GEOMCHG | DIRTY;
30 void rtk_free_widget(rtk_widget *w)
34 if(w->type == RTK_WIN) {
36 rtk_widget *c = w->win.clist;
37 w->win.clist = w->win.clist->any.next;
46 int rtk_type(rtk_widget *w)
51 void rtk_move(rtk_widget *w, int x, int y)
55 w->any.flags |= GEOMCHG;
58 void rtk_pos(rtk_widget *w, int *xptr, int *yptr)
64 void rtk_resize(rtk_widget *w, int xsz, int ysz)
68 w->any.flags |= GEOMCHG;
71 void rtk_size(rtk_widget *w, int *xptr, int *yptr)
74 *yptr = w->any.height;
77 int rtk_set_text(rtk_widget *w, const char *str)
80 char *s = strdup(str);
86 calc_widget_rect(w, &rect);
87 rtk_resize(w, rect.width, rect.height);
91 const char *rtk_get_text(rtk_widget *w)
96 void rtk_set_value(rtk_widget *w, int val)
101 int rtk_get_value(rtk_widget *w)
106 void rtk_set_callback(rtk_widget *w, rtk_callback cbfunc, void *cls)
108 w->any.cbfunc = cbfunc;
112 void rtk_win_layout(rtk_widget *w, int layout)
114 w->win.layout = layout;
117 void rtk_win_clear(rtk_widget *w)
121 RTK_ASSERT_TYPE(w, RTK_WIN);
123 while(w->win.clist) {
125 w->win.clist = w->win.clist->any.next;
126 rtk_free_widget(tmp);
129 w->win.clist = w->win.ctail = 0;
132 void rtk_win_add(rtk_widget *par, rtk_widget *child)
134 RTK_ASSERT_TYPE(par, RTK_WIN);
136 if(rtk_win_has(par, child)) {
141 rtk_win_rm(child->any.par, child);
145 par->win.ctail->any.next = child;
146 par->win.ctail = child;
148 par->win.clist = par->win.ctail = child;
152 child->any.par = par;
155 void rtk_win_rm(rtk_widget *par, rtk_widget *child)
157 rtk_widget *prev, dummy;
159 RTK_ASSERT_TYPE(par, RTK_WIN);
161 dummy.any.next = par->win.clist;
163 while(prev->any.next) {
164 if(prev->any.next == child) {
165 if(!child->any.next) {
166 par->win.ctail = prev;
168 prev->any.next = child->any.next;
171 prev = prev->any.next;
173 par->win.clist = dummy.any.next;
176 int rtk_win_has(rtk_widget *par, rtk_widget *child)
180 RTK_ASSERT_TYPE(par, RTK_WIN);
192 /* --- button functions --- */
194 void rtk_bn_set_icon(rtk_widget *w, rtk_icon *icon)
198 RTK_ASSERT_TYPE(w, RTK_BUTTON);
201 calc_widget_rect(w, &rect);
202 rtk_resize(w, rect.width, rect.height);
205 rtk_icon *rtk_bn_get_icon(rtk_widget *w)
207 RTK_ASSERT_TYPE(w, RTK_BUTTON);
211 /* --- constructors --- */
213 rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y, int width, int height)
217 if(!(w = rtk_create_widget())) {
221 if(par) rtk_win_add(par, w);
222 rtk_set_text(w, title);
224 rtk_resize(w, width, height);
228 rtk_widget *rtk_create_button(rtk_widget *par, const char *str, rtk_callback cbfunc)
232 if(!(w = rtk_create_widget())) {
235 w->type = RTK_BUTTON;
236 if(par) rtk_win_add(par, w);
237 rtk_set_text(w, str);
238 rtk_set_callback(w, cbfunc, 0);
242 rtk_widget *rtk_create_iconbutton(rtk_widget *par, rtk_icon *icon, rtk_callback cbfunc)
246 if(!(w = rtk_create_widget())) {
249 w->type = RTK_BUTTON;
250 if(par) rtk_win_add(par, w);
251 rtk_bn_set_icon(w, icon);
252 rtk_set_callback(w, cbfunc, 0);
256 rtk_widget *rtk_create_label(rtk_widget *par, const char *text)
260 if(!(w = rtk_create_widget())) {
264 if(par) rtk_win_add(par, w);
265 rtk_set_text(w, text);
269 rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_callback cbfunc)
273 if(!(w = rtk_create_widget())) {
276 w->type = RTK_CHECKBOX;
277 if(par) rtk_win_add(par, w);
278 rtk_set_text(w, text);
279 rtk_set_value(w, chk ? 1 : 0);
280 rtk_set_callback(w, cbfunc, 0);
284 rtk_widget *rtk_create_separator(rtk_widget *par)
288 if(!(w = rtk_create_widget())) {
292 if(par) rtk_win_add(par, w);
297 /* --- icon functions --- */
298 rtk_iconsheet *rtk_load_iconsheet(const char *fname)
302 if(!(is = malloc(sizeof *is))) {
307 if(!(is->pixels = img_load_pixels(fname, &is->width, &is->height, IMG_FMT_RGBA32))) {
314 void rtk_free_iconsheet(rtk_iconsheet *is)
318 img_free_pixels(is->pixels);
322 is->icons = is->icons->next;
329 rtk_icon *rtk_define_icon(rtk_iconsheet *is, const char *name, int x, int y, int w, int h)
333 if(!(icon = malloc(sizeof *icon))) {
336 if(!(icon->name = strdup(name))) {
342 icon->scanlen = is->width;
343 icon->pixels = is->pixels + y * is->width + x;
349 #define OFFS (BEVELSZ + PAD)
350 #define CHKBOXSZ (BEVELSZ * 2 + 8)
352 static void calc_widget_rect(rtk_widget *w, rtk_rect *rect)
354 rtk_rect txrect = {0};
360 gfx.textrect(w->any.text, &txrect);
365 rect->width = w->any.width;
366 rect->height = w->any.height;
371 rect->width = w->bn.icon->width + OFFS * 2;
372 rect->height = w->bn.icon->height + OFFS * 2;
374 rect->width = txrect.width + OFFS * 2;
375 rect->height = txrect.height + OFFS * 2;
380 rect->width = txrect.width + CHKBOXSZ + OFFS * 2 + PAD;
381 rect->height = txrect.height + OFFS * 2;
385 rect->width = txrect.width + PAD * 2;
386 rect->height = txrect.height + PAD * 2;
390 if(w->any.par->win.layout == RTK_VBOX) {
391 rect->width = w->any.par->any.width - PAD * 2;
392 rect->height = PAD * 4 + BEVELSZ * 2;
393 } else if(w->any.par->win.layout == RTK_HBOX) {
394 rect->width = PAD * 4 + BEVELSZ * 2;
395 rect->height = w->any.par->any.height - PAD * 2;
397 rect->width = rect->height = 0;
402 rect->width = rect->height = 0;
406 static int need_relayout(rtk_widget *w)
410 if(w->any.flags & GEOMCHG) {
414 if(w->any.type == RTK_WIN) {
417 if(need_relayout(c)) {
426 static void calc_layout(rtk_widget *w)
432 if(w->any.type == RTK_WIN && w->win.layout != RTK_NONE) {
440 if(w->win.layout == RTK_VBOX) {
441 y += c->any.height + PAD * 2;
443 x += c->any.width + PAD * 2;
450 calc_widget_rect(w, &rect);
451 w->any.width = rect.width;
452 w->any.height = rect.height;
454 w->any.flags = (w->any.flags & ~GEOMCHG) | DIRTY;
457 void rtk_draw_widget(rtk_widget *w)
459 if(need_relayout(w)) {
463 switch(w->any.type) {
484 w->any.flags &= ~DIRTY;
487 static void widget_rect(rtk_widget *w, rtk_rect *rect)
491 rect->width = w->any.width;
492 rect->height = w->any.height;
495 static void abs_pos(rtk_widget *w, int *xpos, int *ypos)
503 abs_pos(w->any.par, &px, &py);
512 #define COL_BG 0xff666666
513 #define COL_LBEV 0xffaaaaaa
514 #define COL_SBEV 0xff222222
515 #define COL_TEXT 0xff000000
517 static void hline(int x, int y, int sz, uint32_t col)
524 gfx.fill(&rect, col);
527 static void vline(int x, int y, int sz, uint32_t col)
534 gfx.fill(&rect, col);
537 enum {FRM_SOLID, FRM_OUTSET, FRM_INSET};
539 static void draw_frame(rtk_rect *rect, int type)
545 tlcol = brcol = 0xff000000;
559 hline(rect->x, rect->y, rect->width, tlcol);
560 vline(rect->x, rect->y + 1, rect->height - 2, tlcol);
561 hline(rect->x, rect->y + rect->height - 1, rect->width, brcol);
562 vline(rect->x + rect->width - 1, rect->y + 1, rect->height - 2, brcol);
565 static void draw_window(rtk_widget *w)
570 widget_rect(w, &rect);
571 gfx.fill(&rect, COL_BG);
580 static void draw_button(rtk_widget *w)
584 widget_rect(w, &rect);
585 abs_pos(w, &rect.x, &rect.y);
587 if(rect.width > 2 && rect.height > 2) {
588 draw_frame(&rect, FRM_OUTSET);
596 gfx.fill(&rect, COL_BG);
598 gfx.blit(rect.x + OFFS, rect.y + OFFS, w->bn.icon);
600 gfx.fill(&rect, 0xff802020);
604 static void draw_checkbox(rtk_widget *w)
608 static void draw_separator(rtk_widget *w)
610 rtk_widget *win = w->any.par;
615 widget_rect(w, &rect);
616 abs_pos(w, &rect.x, &rect.y);
618 switch(win->win.layout) {
633 draw_frame(&rect, FRM_INSET);