From c4a043b45ff38d532579cfdf0b6a7e3f50527559 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 6 Jun 2023 08:42:48 +0300 Subject: [PATCH] gui stuff --- .gitignore | 4 +- src/rtk.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/rtk.h | 39 ++++++- src/rtk_impl.h | 36 +++++-- src/sizeint.h | 35 ++++++ src/util.h | 2 +- 6 files changed, 416 insertions(+), 22 deletions(-) create mode 100644 src/sizeint.h diff --git a/.gitignore b/.gitignore index c4b7b45..614b0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ *.swp *.a *.lib -retrorend +retroray +*.cfg +data/ *.exe diff --git a/src/rtk.c b/src/rtk.c index b4840d1..43de80d 100644 --- a/src/rtk.c +++ b/src/rtk.c @@ -1,7 +1,17 @@ #include #include +#include "imago2.h" #include "rtk_impl.h" +static rtk_draw_ops gfx; + +static void calc_widget_rect(rtk_widget *w, rtk_rect *rect); + +void rtk_setup(rtk_draw_ops *drawop) +{ + gfx = *drawop; +} + rtk_widget *rtk_create_widget(void) { rtk_widget *w; @@ -9,7 +19,7 @@ rtk_widget *rtk_create_widget(void) if(!(w = calloc(1, sizeof *w))) { return 0; } - w->any.visible = w->any.enabled = 1; + w->any.flags = VISIBLE | ENABLED | GEOMCHG | DIRTY; return w; } @@ -38,6 +48,7 @@ void rtk_move(rtk_widget *w, int x, int y) { w->any.x = x; w->any.y = y; + w->any.flags |= GEOMCHG; } void rtk_pos(rtk_widget *w, int *xptr, int *yptr) @@ -50,6 +61,7 @@ void rtk_resize(rtk_widget *w, int xsz, int ysz) { w->any.width = xsz; w->any.height = ysz; + w->any.flags |= GEOMCHG; } void rtk_size(rtk_widget *w, int *xptr, int *yptr) @@ -60,11 +72,15 @@ void rtk_size(rtk_widget *w, int *xptr, int *yptr) int rtk_set_text(rtk_widget *w, const char *str) { + rtk_rect rect; char *s = strdup(str); if(!s) return -1; free(w->any.text); w->any.text = s; + + calc_widget_rect(w, &rect); + rtk_resize(w, rect.width, rect.height); return 0; } @@ -73,6 +89,16 @@ const char *rtk_get_text(rtk_widget *w) return w->any.text; } +void rtk_set_value(rtk_widget *w, int val) +{ + w->any.value = val; +} + +int rtk_get_value(rtk_widget *w) +{ + return w->any.value; +} + void rtk_set_callback(rtk_widget *w, rtk_callback cbfunc, void *cls) { w->any.cbfunc = cbfunc; @@ -159,27 +185,309 @@ int rtk_win_has(rtk_widget *par, rtk_widget *child) return 0; } -rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y, int w, int h) +/* --- button functions --- */ + +void rtk_bn_set_icon(rtk_widget *w, rtk_icon *icon) { - return 0; + RTK_ASSERT_TYPE(w, RTK_BUTTON); + w->bn.icon = icon; +} + +rtk_icon *rtk_bn_get_icon(rtk_widget *w) +{ + RTK_ASSERT_TYPE(w, RTK_BUTTON); + return w->bn.icon; +} + +/* --- constructors --- */ + +rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y, int width, int height) +{ + rtk_widget *w; + + if(!(w = rtk_create_widget())) { + return 0; + } + if(par) rtk_win_add(par, w); + rtk_set_text(w, title); + rtk_move(w, x, y); + rtk_resize(w, width, height); + return w; } rtk_widget *rtk_create_button(rtk_widget *par, const char *str, rtk_callback cbfunc) { - return 0; + rtk_widget *w; + + if(!(w = rtk_create_widget())) { + return 0; + } + if(par) rtk_win_add(par, w); + rtk_set_text(w, str); + rtk_set_callback(w, cbfunc, 0); + return w; } -rtk_widget *rtk_create_iconbutton(rtk_widget *par, struct image *img, rtk_callback cbfunc) +rtk_widget *rtk_create_iconbutton(rtk_widget *par, rtk_icon *icon, rtk_callback cbfunc) { - return 0; + rtk_widget *w; + + if(!(w = rtk_create_widget())) { + return 0; + } + if(par) rtk_win_add(par, w); + rtk_bn_set_icon(w, icon); + rtk_set_callback(w, cbfunc, 0); + return w; } rtk_widget *rtk_create_label(rtk_widget *par, const char *text) { - return 0; + rtk_widget *w; + + if(!(w = rtk_create_widget())) { + return 0; + } + if(par) rtk_win_add(par, w); + rtk_set_text(w, text); + return w; } rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_callback cbfunc) { + rtk_widget *w; + + if(!(w = rtk_create_widget())) { + return 0; + } + if(par) rtk_win_add(par, w); + rtk_set_text(w, text); + rtk_set_value(w, chk ? 1 : 0); + rtk_set_callback(w, cbfunc, 0); + return w; +} + +/* --- icon functions --- */ +rtk_iconsheet *rtk_load_iconsheet(const char *fname) +{ + rtk_iconsheet *is; + + if(!(is = malloc(sizeof *is))) { + return 0; + } + is->icons = 0; + + if(!(is->pixels = img_load_pixels(fname, &is->width, &is->height, IMG_FMT_RGBA32))) { + free(is); + return 0; + } + return is; +} + +void rtk_free_iconsheet(rtk_iconsheet *is) +{ + rtk_icon *icon; + + img_free_pixels(is->pixels); + + while(is->icons) { + icon = is->icons; + is->icons = is->icons->next; + free(icon->name); + free(icon); + } + free(is); +} + +rtk_icon *rtk_define_icon(rtk_iconsheet *is, const char *name, int x, int y, int w, int h) +{ + rtk_icon *icon; + + if(!(icon = malloc(sizeof *icon))) { + return 0; + } + if(!(icon->name = strdup(name))) { + free(icon); + return 0; + } + icon->width = w; + icon->height = h; + icon->scanlen = is->width; + icon->pixels = is->pixels + y * is->width + x; + return icon; +} + +#define BEVELSZ 1 +#define PAD 2 +#define OFFS (BEVELSZ + PAD) +#define CHKBOXSZ (BEVELSZ * 2 + 8) + +static void calc_widget_rect(rtk_widget *w, rtk_rect *rect) +{ + rtk_rect txrect = {0}; + + rect->x = w->any.x; + rect->y = w->any.y; + + if(w->any.text) { + gfx.textrect(w->any.text, &txrect); + } + + switch(w->type) { + case RTK_BUTTON: + if(w->bn.icon) { + rect->width = w->bn.icon->width + OFFS * 2; + rect->height = w->bn.icon->height + OFFS * 2; + } else { + rect->width = txrect.width + OFFS * 2; + rect->height = txrect.height + OFFS * 2; + } + break; + + case RTK_CHECKBOX: + rect->width = txrect.width + CHKBOXSZ + OFFS * 2 + PAD; + rect->height = txrect.height + OFFS * 2; + break; + + case RTK_LABEL: + rect->width = txrect.width + PAD * 2; + rect->height = txrect.height + PAD * 2; + break; + + default: + rect->width = rect->height = 0; + } +} + +static int need_relayout(rtk_widget *w) +{ + rtk_widget *c; + + if(w->any.flags & GEOMCHG) { + return 1; + } + + if(w->any.type == RTK_WIN) { + c = w->win.clist; + while(c) { + if(need_relayout(c)) { + return 1; + } + c = c->any.next; + } + } return 0; } + +static void calc_layout(rtk_widget *w) +{ + int x, y; + rtk_widget *c; + + if(w->any.type == RTK_WIN && w->win.layout != RTK_NONE) { + x = y = PAD; + + c = w->win.clist; + while(c) { + rtk_move(c, x, y); + calc_layout(c); + + if(w->win.layout == RTK_VBOX) { + y += c->any.height + PAD; + } else { + x += c->any.width + PAD; + } + + c = c->any.next; + } + } + + w->any.flags = (w->any.flags & ~GEOMCHG) | DIRTY; +} + +static void draw_window(rtk_widget *w); +static void draw_button(rtk_widget *w); +static void draw_checkbox(rtk_widget *w); + +void rtk_draw_widget(rtk_widget *w) +{ + if(need_relayout(w)) { + calc_layout(w); + } + + switch(w->any.type) { + case RTK_WIN: + draw_window(w); + break; + + case RTK_BUTTON: + draw_button(w); + break; + + case RTK_CHECKBOX: + draw_checkbox(w); + break; + + default: + break; + } + + w->any.flags &= ~DIRTY; +} + +static void widget_rect(rtk_widget *w, rtk_rect *rect) +{ + rect->x = w->any.x; + rect->y = w->any.y; + rect->width = w->any.width; + rect->height = w->any.height; +} + +static void abs_pos(rtk_widget *w, int *xpos, int *ypos) +{ + int x, y, px, py; + + x = w->any.x; + y = w->any.y; + + if(w->any.par) { + abs_pos(w->any.par, &px, &py); + x += px; + y += py; + } + + *xpos = x; + *ypos = y; +} + +#define COL_BG 0xa0a0a0 +#define COL_LBEV 0xcccccc +#define COL_SBEV 0x202020 +#define COL_TEXT 0 + +static void draw_window(rtk_widget *w) +{ + rtk_rect rect; + + widget_rect(w, &rect); + gfx.fill(&rect, COL_BG); +} + +static void draw_button(rtk_widget *w) +{ + rtk_rect rect; + + widget_rect(w, &rect); + abs_pos(w, &rect.x, &rect.y); + + gfx.fill(&rect, COL_BG); + if(w->bn.icon) { + gfx.blit(rect.x + OFFS, rect.y + OFFS, w->bn.icon); + } else { + gfx.fill(&rect, 0x802020); + } +} + +static void draw_checkbox(rtk_widget *w) +{ +} diff --git a/src/rtk.h b/src/rtk.h index c7ecf15..58cccad 100644 --- a/src/rtk.h +++ b/src/rtk.h @@ -1,17 +1,33 @@ #ifndef RTK_H_ #define RTK_H_ -struct image; - /* widget type */ enum { RTK_ANY, RTK_WIN, RTK_BUTTON, RTK_LABEL, RTK_CHECKBOX, RTK_SLIDER }; /* window layout */ enum { RTK_NONE, RTK_VBOX, RTK_HBOX }; typedef union rtk_widget rtk_widget; +typedef struct rtk_icon rtk_icon; +typedef struct rtk_iconsheet rtk_iconsheet; + +typedef struct rtk_rect { + int x, y, width, height; +} rtk_rect; + +typedef struct rtk_draw_ops { + void (*fill)(rtk_rect *rect, uint32_t color); + void (*blit)(int x, int y, rtk_icon *icon); + void (*drawtext)(int x, int y, const char *str); + void (*textrect)(const char *str, rtk_rect *rect); +} rtk_draw_ops; typedef void (*rtk_callback)(rtk_widget*, void*); +/* global state */ +void rtk_setup(rtk_draw_ops *drawop); + +/* widget functions */ + rtk_widget *rtk_create_widget(void); void rtk_free_widget(rtk_widget *w); @@ -25,6 +41,9 @@ void rtk_size(rtk_widget *w, int *xptr, int *yptr); int rtk_set_text(rtk_widget *w, const char *str); const char *rtk_get_text(rtk_widget *w); +void rtk_set_value(rtk_widget *w, int val); +int rtk_get_value(rtk_widget *w); + void rtk_set_callback(rtk_widget *w, rtk_callback cbfunc, void *cls); /* window functions */ @@ -34,10 +53,24 @@ void rtk_win_add(rtk_widget *par, rtk_widget *child); void rtk_win_rm(rtk_widget *par, rtk_widget *child); int rtk_win_has(rtk_widget *par, rtk_widget *child); +/* button functions */ +void rtk_bn_set_icon(rtk_widget *w, rtk_icon *icon); +rtk_icon *rtk_bn_get_icon(rtk_widget *w); + rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y, int w, int h); rtk_widget *rtk_create_button(rtk_widget *par, const char *str, rtk_callback cbfunc); -rtk_widget *rtk_create_iconbutton(rtk_widget *par, struct image *img, rtk_callback cbfunc); +rtk_widget *rtk_create_iconbutton(rtk_widget *par, rtk_icon *icon, rtk_callback cbfunc); rtk_widget *rtk_create_label(rtk_widget *par, const char *text); rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_callback cbfunc); +/* icon functions */ +rtk_iconsheet *rtk_load_iconsheet(const char *fname); +void rtk_free_iconsheet(rtk_iconsheet *is); + +rtk_icon *rtk_define_icon(rtk_iconsheet *is, const char *name, int x, int y, int w, int h); + + +void rtk_draw_widget(rtk_widget *w); + + #endif /* RTK_H_ */ diff --git a/src/rtk_impl.h b/src/rtk_impl.h index 17431ee..d9ee120 100644 --- a/src/rtk_impl.h +++ b/src/rtk_impl.h @@ -2,17 +2,26 @@ #define RTK_IMPL_H_ #include +#include "inttypes.h" #include "rtk.h" +enum { + VISIBLE = 0x001, + ENABLED = 0x002, + GEOMCHG = 0x100, + DIRTY = 0x200 +}; + typedef struct rtk_any { int type; int x, y, width, height; char *text; - int visible, enabled; + int value; + unsigned int flags; union rtk_widget *par, *next; rtk_callback cbfunc; void *cbcls; -} rtk_any, rtk_label; +} rtk_any; typedef struct rtk_window { rtk_any any; @@ -22,23 +31,30 @@ typedef struct rtk_window { typedef struct rtk_button { rtk_any any; - struct image *icon; + rtk_icon *icon; } rtk_button; -typedef struct rtk_checkbox { - rtk_any any; - int chk; -} rtk_checkbox; - typedef union rtk_widget { int type; rtk_any any; rtk_window win; rtk_button bn; - rtk_label lb; - rtk_checkbox chk; } rtk_widget; +typedef struct rtk_icon { + char *name; + int width, height, scanlen; + uint32_t *pixels; + + struct rtk_icon *next; +} rtk_icon; + +typedef struct rtk_iconsheet { + int width, height; + uint32_t *pixels; + + struct rtk_icon *icons; +} rtk_iconsheet; #define RTK_ASSERT_TYPE(w, t) assert(w->any.type == t) diff --git a/src/sizeint.h b/src/sizeint.h new file mode 100644 index 0000000..e1f6569 --- /dev/null +++ b/src/sizeint.h @@ -0,0 +1,35 @@ +#ifndef SIZEINT_H_ +#define SIZEINT_H_ + +/* for C99 or selected toolchain versions we can use stdint.h */ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) || \ + (defined(__WATCOMC__) && __WATCOMC__ >= 1200) +#include + +#elif defined(__DOS__) && defined(__WATCOMC__) && __WATCOMC__ < 1200 +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef long int32_t; +typedef unsigned long uint32_t; +typedef long intptr_t; +typedef unsigned long uintptr_t; + +#elif defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef long intptr_t; +typedef unsigned long uintptr_t; + +#else +#include +#endif + + +#endif /* SIZEINT_H_ */ diff --git a/src/util.h b/src/util.h index 8eebd33..7f418a9 100644 --- a/src/util.h +++ b/src/util.h @@ -19,7 +19,7 @@ along with this program. If not, see . #define UTIL_H_ #include -#include "byteord.h" /* from imago, to sort out the sized int types mess */ +#include "sizeint.h" #if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__) #include -- 1.7.10.4