gui stuff
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 6 Jun 2023 05:42:48 +0000 (08:42 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 6 Jun 2023 05:42:48 +0000 (08:42 +0300)
.gitignore
src/rtk.c
src/rtk.h
src/rtk_impl.h
src/sizeint.h [new file with mode: 0644]
src/util.h

index c4b7b45..614b0ad 100644 (file)
@@ -3,5 +3,7 @@
 *.swp
 *.a
 *.lib
-retrorend
+retroray
+*.cfg
+data/
 *.exe
index b4840d1..43de80d 100644 (file)
--- a/src/rtk.c
+++ b/src/rtk.c
@@ -1,7 +1,17 @@
 #include <stdlib.h>
 #include <string.h>
+#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)
+{
+}
index c7ecf15..58cccad 100644 (file)
--- 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_ */
index 17431ee..d9ee120 100644 (file)
@@ -2,17 +2,26 @@
 #define RTK_IMPL_H_
 
 #include <assert.h>
+#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 (file)
index 0000000..e1f6569
--- /dev/null
@@ -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 <stdint.h>
+
+#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 <sys/types.h>
+#endif
+
+
+#endif /* SIZEINT_H_ */
index 8eebd33..7f418a9 100644 (file)
@@ -19,7 +19,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #define UTIL_H_
 
 #include <stdlib.h>
-#include "byteord.h"   /* from imago, to sort out the sized int types mess */
+#include "sizeint.h"
 
 #if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
 #include <malloc.h>