initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 22 Nov 2021 21:10:18 +0000 (23:10 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 22 Nov 2021 21:10:18 +0000 (23:10 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
example.c [new file with mode: 0644]
src/widget.c [new file with mode: 0644]
src/widget.h [new file with mode: 0644]
src/window.c [new file with mode: 0644]
src/windtk.c [new file with mode: 0644]
src/windtk.h [new file with mode: 0644]
src/wtimpl.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..2a4e0bf
--- /dev/null
@@ -0,0 +1,4 @@
+*.o
+*.d
+*.swp
+example
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..adce8a2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+src = $(wildcard src/*.c) example.c
+obj = $(src:.c=.o)
+dep = $(src:.c=.d)
+bin = example
+
+CFLAGS = -pedantic -Wall -g -Isrc -MMD
+LDFLAGS = -lGL -lglut
+
+$(bin): $(obj)
+       $(CC) -o $@ $(obj) $(LDFLAGS)
+
+-include $(dep)
+
+.PHONY: clean
+clean:
+       rm -f $(obj)
diff --git a/example.c b/example.c
new file mode 100644 (file)
index 0000000..2d13dc5
--- /dev/null
+++ b/example.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+#include "windtk.h"
+
+static void display(void);
+static void reshape(int x, int y);
+static void keypress(unsigned char key, int x, int y);
+static void keyrelease(unsigned char key, int x, int y);
+static void mouse(int bn, int st, int x, int y);
+static void motion(int x, int y);
+
+static int gfx_newcol(int r, int g, int b);
+static void gfx_color(int c);
+static void gfx_fillrect(struct wt_rect *r);
+static void gfx_line(int x0, int y0, int x1, int y1);
+
+static struct wt_graphics gfx = {
+       gfx_newcol, gfx_color,
+       gfx_fillrect,
+       gfx_line
+};
+
+int main(int argc, char **argv)
+{
+       glutInit(&argc, argv);
+       glutInitWindowSize(800, 600);
+       glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+       glutCreateWindow("windtk example");
+
+       glutDisplayFunc(display);
+       glutReshapeFunc(reshape);
+       glutKeyboardFunc(keypress);
+       glutKeyboardUpFunc(keyrelease);
+       glutMouseFunc(mouse);
+       glutMotionFunc(motion);
+       glutPassiveMotionFunc(motion);
+
+       if(wt_init(800, 600, &gfx)) {
+               return 1;
+       }
+
+       glutMainLoop();
+       return 0;
+}
+
+static void display(void)
+{
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       glutSwapBuffers();
+}
+
+static void reshape(int x, int y)
+{
+       glViewport(0, 0, x, y);
+       glMatrixMode(GL_PROJECTION);
+       glLoadIdentity();
+       glOrtho(0, x, y, 0, -1, 1);
+
+       wt_viewport(0, 0, x, y);
+}
+
+static void keypress(unsigned char key, int x, int y)
+{
+       if(key == 27) exit(0);
+
+       wt_inp_key(key, 1);
+}
+
+static void keyrelease(unsigned char key, int x, int y)
+{
+       wt_inp_key(key, 0);
+}
+
+static void mouse(int bn, int st, int x, int y)
+{
+       wt_inp_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y);
+}
+
+static void motion(int x, int y)
+{
+       wt_inp_motion(x, y);
+}
+
+/* ------ graphics callbacks -------- */
+static float colors[32][3];
+static int maxcol;
+
+static int gfx_newcol(int r, int g, int b)
+{
+       if(maxcol >= 32) return -1;
+       colors[maxcol][0] = r / 255.0f;
+       colors[maxcol][1] = g / 255.0f;
+       colors[maxcol][2] = b / 255.0f;
+       return maxcol++;
+}
+
+static void gfx_color(int c)
+{
+       glColor3fv(colors[c]);
+}
+
+static void gfx_fillrect(struct wt_rect *r)
+{
+       glBegin(GL_QUADS);
+       glVertex2f(r->x, r->y);
+       glVertex2f(r->x + r->width, r->y);
+       glVertex2f(r->x + r->width, r->y + r->height);
+       glVertex2f(r->x, r->y + r->height);
+       glEnd();
+}
+
+static void gfx_line(int x0, int y0, int x1, int y1)
+{
+       glBegin(GL_LINES);
+       glVertex2f(x0, y0);
+       glVertex2f(x1, y1);
+       glEnd();
+}
diff --git a/src/widget.c b/src/widget.c
new file mode 100644 (file)
index 0000000..07643db
--- /dev/null
@@ -0,0 +1,230 @@
+#include <stdlib.h>
+#include <string.h>
+#include "wtimpl.h"
+
+wt_widget *wt_alloc_widget(wt_widget *par)
+{
+       wt_widget *w;
+       if(!(w = wt_zalloc(sizeof *w))) {
+               return 0;
+       }
+       w->type = WT_TYPE_WIDGET;
+
+       if(par) {
+               wt_add_child(par, w);
+       }
+       return w;
+}
+
+void wt_free_widget(wt_widget *w)
+{
+       if(w) {
+               wt_free(w->text);
+               wt_free(w->child);
+               wt_free(w);
+       }
+}
+
+void wt_free_tree(wt_widget *tree)
+{
+       int i;
+
+       if(!tree) return;
+
+       for(i=0; i<tree->num_child; i++) {
+               wt_free_tree(tree->child[i]);
+       }
+       wt_free_widget(tree);
+}
+
+int wt_type(wt_widget *w)
+{
+       return w->type;
+}
+
+int wt_set_text(wt_widget *w, const char *text)
+{
+       char *s;
+
+       if(!(s = wt_alloc(strlen(text) + 1))) {
+               return -1;
+       }
+       strcpy(s, text);
+       wt_free(w->text);
+       w->text = s;
+       return 0;
+}
+
+const char *wt_text(wt_widget *w)
+{
+       return w->text;
+}
+
+static int find_child(wt_widget *w, wt_widget *c)
+{
+       int i;
+       for(i=0; i<w->num_child; i++) {
+               if(w->child[i] == c) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+int wt_add_child(wt_widget *w, wt_widget *c)
+{
+       if(find_child(w, c) != -1) {
+               return 0;
+       }
+       if(c->parent) {
+               wt_remove_child(c->parent, c);
+       }
+
+       if(w->num_child >= w->max_child) {
+               void *newarr;
+               int newsz = w->max_child ? w->max_child << 1 : 8;
+               if(!(newarr = wt_alloc(newsz * sizeof *w->child))) {
+                       return -1;
+               }
+               memcpy(newarr, w->child, w->num_child * sizeof *w->child);
+               wt_free(w->child);
+               w->child = newarr;
+               w->max_child = newsz;
+       }
+
+       w->child[w->num_child++] = c;
+       return 0;
+}
+
+int wt_remove_child(wt_widget *w, wt_widget *c)
+{
+       int idx;
+
+       if(!w->num_child || (idx = find_child(w, c)) == -1) {
+               return -1;
+       }
+       w->child[idx] = w->child[--w->num_child];
+
+       if(w->max_child > 8 && w->num_child < w->max_child / 3) {
+               void *newarr;
+               int newsz = w->max_child >> 1;
+               if(!(newarr = wt_alloc(newsz * sizeof *w->child))) {
+                       return -1;
+               }
+               memcpy(newarr, w->child, w->num_child * sizeof *w->child);
+               wt_free(w->child);
+               w->child = newarr;
+               w->max_child = newsz;
+       }
+       return 0;
+}
+
+wt_widget *wt_parent(wt_widget *w)
+{
+       return w->parent;
+}
+
+wt_widget *wt_widget_window(wt_widget *w)
+{
+       wt_widget *par = w;
+       while(par && par->type != WT_TYPE_WINDOW) {
+               par = par->parent;
+       }
+       return par;
+}
+
+int wt_child_count(wt_widget *w)
+{
+       return w->num_child;
+}
+
+wt_widget *wt_child(wt_widget *w, int idx)
+{
+       if(idx < 0 || idx >= w->num_child) {
+               return 0;
+       }
+       return w->child[idx];
+}
+
+void wt_move(wt_widget *w, int x, int y)
+{
+       w->rect.x = x;
+       w->rect.y = y;
+       /* TODO: invalidate something */
+}
+
+void wt_resize(wt_widget *w, int x, int y)
+{
+       w->rect.width = x;
+       w->rect.height = y;
+       /* TODO: invalidate something */
+}
+
+int *wt_position(wt_widget *w, int *xret, int *yret)
+{
+       if(xret) *xret = w->rect.x;
+       if(yret) *yret = w->rect.y;
+       return &w->rect.x;
+}
+
+int *wt_size(wt_widget *w, int *xret, int *yret)
+{
+       if(xret) *xret = w->rect.width;
+       if(yret) *yret = w->rect.height;
+       return &w->rect.width;
+}
+
+int wt_hittest(wt_widget *w, int x, int y)
+{
+       return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.width &&
+               y < w->rect.y + w->rect.height;
+}
+
+wt_widget *wt_widget_at(int x, int y)
+{
+       int i;
+       wt_widget *w, *c;
+
+       if(!wt_hittest(wt->root, x, y)) {
+               return 0;
+       }
+
+       w = 0;
+       c = wt->root;
+       do {
+               w = c;
+               c = 0;
+               for(i=0; i<w->num_child; i++) {
+                       if(wt_hittest(w->child[i], x, y)) {
+                               c = w->child[i];
+                               break;
+                       }
+               }
+       } while(c);
+
+       return w;
+}
+
+/*
+void wt_layout(wt_widget *w, int layout);
+void wt_padding(wt_widget *w, int pad);
+void wt_relayout(wt_widget *w);
+
+void wt_focus(wt_widget *w);
+void wt_unfocus(wt_widget *w);
+int wt_isfocused(wt_widget *w);
+
+void wt_hover(wt_widget *w);
+void wt_unhover(wt_widget *w);
+int wt_ishover(wt_widget *w);
+
+void wt_enable(wt_widget *w);
+void wt_disable(wt_widget *w);
+int wt_isenabled(wt_widget *w);
+*/
+
+void wt_callback(wt_widget *w, int type, wt_callback_func func, void *cls)
+{
+       w->cb[type] = func;
+       w->cbcls[type] = cls;
+}
diff --git a/src/widget.h b/src/widget.h
new file mode 100644 (file)
index 0000000..0a978cf
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef WIDGET_H_
+#define WIDGET_H_
+
+#include "windtk.h"
+
+struct wt_widget {
+       int type;
+       char *text;
+       struct wt_rect rect;
+
+       struct wt_widget *parent;
+       struct wt_widget **child;       /* dynamic array */
+       int num_child, max_child;
+       int layout;
+
+       wt_callback_func cb[WT_NUM_CALLBACKS];
+       void *cbcls[WT_NUM_CALLBACKS];
+
+       void (*draw)(struct wt_widget *w);
+       void (*click)(struct wt_widget *w);
+       void (*keypress)(struct wt_widget *w, int key);
+       void (*mbutton)(struct wt_widget *w, int bn, int st, int x, int y);
+       void (*mmotion)(struct wt_widget *w, int x, int y);
+};
+
+#endif /* WIDGET_H_ */
diff --git a/src/window.c b/src/window.c
new file mode 100644 (file)
index 0000000..a103ed4
--- /dev/null
@@ -0,0 +1,26 @@
+#include "wtimpl.h"
+
+static void draw_win(wt_widget *w);
+
+wt_widget *wt_window(wt_widget *par, const char *title, int style, int x, int y, int xsz, int ysz)
+{
+       wt_widget *w;
+
+       if(!(w = wt_alloc_widget(par))) {
+               return 0;
+       }
+       w->type = WT_TYPE_WINDOW;
+       wt_set_text(w, title);
+       wt_move(w, x, y);
+       wt_resize(w, xsz, ysz);
+       /* TODO: style */
+
+       w->draw = draw_win;
+       return w;
+}
+
+static void draw_win(wt_widget *w)
+{
+       wt_gfx_color(COL_BG);
+       wt_gfx_fillrect(&w->rect);
+}
diff --git a/src/windtk.c b/src/windtk.c
new file mode 100644 (file)
index 0000000..1e4de86
--- /dev/null
@@ -0,0 +1,126 @@
+#include <stdlib.h>
+#include <string.h>
+#include "wtimpl.h"
+
+void *(*wt_alloc)(size_t sz) = malloc;
+void (*wt_free)(void *p) = free;
+
+/* one day I may want to allow multiple contexts */
+static struct wt_context defctx;
+struct wt_context *wt_curctx_ = &defctx;
+
+static unsigned int def_colors[] = {
+       0xf0f0f0,       /* font/foreground */
+       0x333333,       /* background */
+       0x444444,       /* highlight */
+       0x222222,       /* shadow */
+       0x403065,       /* inactive frame */
+       0x54349c,       /* inactive frame highlight */
+       0x221e2c,       /* inactive frame shadow */
+       0x8032aa,       /* active frame */
+       0xb14de8,       /* active frame highlight */
+       0x3b2846,       /* active frame shadow */
+       0
+};
+
+void *wt_zalloc(size_t sz)
+{
+       void *p = wt_alloc(sz);
+       if(p) {
+               memset(p, 0, sz);
+       }
+       return p;
+}
+
+void wt_allocator(void *(*allocfunc)(size_t), void (*freefunc)(void *p))
+{
+       wt_alloc = allocfunc ? allocfunc : malloc;
+       wt_free = freefunc ? freefunc : free;
+}
+
+
+int wt_init(int w, int h, struct wt_graphics *gfx)
+{
+       if(!(wt->root = wt_alloc_widget(0))) {
+               return -1;
+       }
+
+       wt_viewport(0, 0, w, h);
+       wt_graphics(gfx);
+       return 0;
+}
+
+void wt_destroy(void)
+{
+       wt_free_tree(wt->root);
+       wt->root = 0;
+}
+
+void wt_viewport(int x, int y, int w, int h)
+{
+       wt_setrect(&wt->vp, x, y, w, h);
+       wt_move(wt->root, x, y);
+       wt_resize(wt->root, w, h);
+}
+
+void wt_graphics(struct wt_graphics *gfx)
+{
+       int i, r, g, b;
+       wt->gfx = *gfx;
+
+       for(i=0; i<NUM_COLORS; i++) {
+               r = def_colors[i] >> 16;
+               g = (def_colors[i] >> 8) & 0xff;
+               b = def_colors[i] & 0xff;
+               if((wt->colors[i] = gfx->newcolor(r, g, b)) == -1) {
+                       wt->colors[i] = i ? wt->colors[i - 1] : 0;
+               }
+       }
+}
+
+void wt_inp_key(int key, int press)
+{
+}
+
+void wt_inp_mouse(int bn, int st, int x, int y)
+{
+}
+
+void wt_inp_motion(int x, int y)
+{
+}
+
+void wt_gfx_color(int cidx)
+{
+       wt->gfx.color(wt->colors[cidx]);
+}
+
+void wt_gfx_fillrect(struct wt_rect *r)
+{
+       wt->gfx.fillrect(r);
+}
+
+void wt_gfx_frame(struct wt_rect *r, int style, int basecol)
+{
+       wt_gfx_color(basecol);
+       wt_gfx_fillrect(r);
+       wt_gfx_color(style == FRM_OUT ? basecol + 2 : basecol + 1);
+       wt_gfx_line(r->x, r->y + r->height, r->x + r->width - 1, r->y + r->height);
+       wt_gfx_line(r->x + r->width, r->y + 1, r->x + r->width, r->y + r->height);
+       wt_gfx_color(style == FRM_OUT ? basecol + 1 : basecol + 2);
+       wt_gfx_line(r->x, r->y, r->x + r->width, r->y);
+       wt_gfx_line(r->x, r->y + 1, r->x, r->y + r->height - 1);
+}
+
+void wt_gfx_line(int x0, int y0, int x1, int y1)
+{
+       wt->gfx.line(x0, y0, x1, y1);
+}
+
+void wt_setrect(struct wt_rect *r, int x, int y, int w, int h)
+{
+       r->x = x;
+       r->y = y;
+       r->width = w;
+       r->height = h;
+}
diff --git a/src/windtk.h b/src/windtk.h
new file mode 100644 (file)
index 0000000..56ca8a6
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef WINDTK_H_
+#define WINDTK_H_
+
+enum {
+       WT_TYPE_WIDGET,
+       WT_TYPE_WINDOW,
+       WT_TYPE_LABEL,
+       WT_TYPE_BUTTON,
+       WT_TYPE_CHECKBOX,
+       WT_TYPE_TEXTFIELD
+};
+
+enum {
+       WT_KEY_UP = 0x100,
+       WT_KEY_DOWN,
+       WT_KEY_LEFT,
+       WT_KEY_RIGHT,
+       WT_KEY_HOME,
+       WT_KEY_END,
+       WT_KEY_PGUP,
+       WT_KEY_PGDN
+};
+
+enum {
+       WT_WS_DEFAULT,
+       WT_WS_NOFRM
+};
+
+enum {
+       WT_CB_FOCUS,
+       WT_CB_UNFOCUS,
+       WT_CB_MODIFY,
+       WT_CB_CLICK,
+       WT_CB_MBUTTON,
+       WT_CB_MMOTION,
+
+       WT_NUM_CALLBACKS
+};
+
+typedef struct wt_widget wt_widget;
+typedef void (*wt_callback_func)(wt_widget*, void*);
+
+struct wt_image {
+       int width, height;
+       int bpp;
+       int pitch;
+       void *pixels;
+       void *udata;
+};
+
+struct wt_rect {
+       int x, y, width, height;
+};
+
+struct wt_graphics {
+       int (*newcolor)(int r, int g, int b);
+       void (*color)(int c);
+
+       void (*fillrect)(struct wt_rect *rect);
+       void (*line)(int x0, int y0, int x1, int y1);
+
+       int (*newimage)(struct wt_image *img);
+       void (*blit)(int img, int x, int y, int w, int h);
+
+       void (*text)(int font, const char *s, int x, int y);
+       void (*textbox)(int font, const char *s, int x, int y, struct wt_rect *boxret);
+       int (*lineheight)(int font);
+       int (*baseline)(int font);
+};
+
+void wt_allocator(void *(*allocfunc)(size_t), void (*freefunc)(void*));
+
+int wt_init(int w, int h, struct wt_graphics *gfx);
+void wt_destroy(void);
+
+void wt_viewport(int x, int y, int w, int h);
+void wt_graphics(struct wt_graphics *gfx);
+
+void wt_inp_key(int key, int press);
+void wt_inp_mouse(int bn, int st, int x, int y);
+void wt_inp_motion(int x, int y);
+
+wt_widget *wt_alloc_widget(wt_widget *par);
+void wt_free_widget(wt_widget *w);
+void wt_free_tree(wt_widget *tree);
+
+wt_widget *wt_window(wt_widget *par, const char *title, int style, int x, int y, int width, int height);
+wt_widget *wt_label(wt_widget *par, const char *text, int x, int y);
+wt_widget *wt_button(wt_widget *par, const char *text, int x, int y, int width, int height);
+wt_widget *wt_button_cb(wt_widget *par, const char *text, int x, int y, int width,
+               int height,     wt_callback_func cbclick, void *cls);
+wt_widget *wt_checkbox(wt_widget *par, const char *text, int chk, int x, int y, int width, int height);
+wt_widget *wt_checkbox_cb(wt_widget *par, const char *text, int chk, int x, int y,
+               int width, int height, wt_callback_func cbtoggle, void *cls);
+wt_widget *wt_textfield(wt_widget *par, const char *text, int x, int y, int width, int height);
+
+int wt_type(wt_widget *w);
+
+int wt_set_text(wt_widget *w, const char *text);
+const char *wt_text(wt_widget *w);
+
+int wt_add_child(wt_widget *w, wt_widget *c);
+int wt_remove_child(wt_widget *w, wt_widget *c);
+wt_widget *wt_parent(wt_widget *w);                    /* parent widget */
+wt_widget *wt_widget_window(wt_widget *w);     /* first ancestor of type window */
+int wt_child_count(wt_widget *w);                      /* number of children */
+wt_widget *wt_child(wt_widget *w, int idx);    /* get child idx */
+
+void wt_move(wt_widget *w, int x, int y);
+void wt_resize(wt_widget *w, int x, int y);
+int *wt_position(wt_widget *w, int *xret, int *yret);
+int *wt_size(wt_widget *w, int *xret, int *yret);
+
+void wt_layout(wt_widget *w, int layout);
+void wt_padding(wt_widget *w, int pad);
+/* calculates layout of child widgets and updates dimensions */
+void wt_relayout(wt_widget *w);
+
+int wt_hittest(wt_widget *w, int x, int y);
+wt_widget *wt_widget_at(int x, int y);
+
+void wt_focus(wt_widget *w);
+void wt_unfocus(wt_widget *w);
+int wt_isfocused(wt_widget *w);
+
+void wt_hover(wt_widget *w);
+void wt_unhover(wt_widget *w);
+int wt_ishover(wt_widget *w);
+
+void wt_enable(wt_widget *w);
+void wt_disable(wt_widget *w);
+int wt_isenabled(wt_widget *w);
+
+void wt_callback(wt_widget *w, int type, wt_callback_func func, void *cls);
+
+void wt_setrect(struct wt_rect *r, int x, int y, int w, int h);
+
+#endif /* WINDTK_H_ */
diff --git a/src/wtimpl.h b/src/wtimpl.h
new file mode 100644 (file)
index 0000000..d9f3410
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef WTIMPL_H_
+#define WTIMPL_H_
+
+#include <stdlib.h>
+#include "windtk.h"
+#include "widget.h"
+
+enum {
+       COL_FG,
+       COL_BG,
+       COL_BGHI,
+       COL_BGLO,
+       COL_FRM,
+       COL_FRMHI,
+       COL_FRMLO,
+       COL_FFRM,
+       COL_FFRMHI,
+       COL_FFRMLO,
+
+       NUM_COLORS
+};
+
+enum { FRM_OUT, FRM_IN };
+
+struct wt_context {
+       struct wt_graphics gfx;
+       struct wt_rect vp;
+       wt_widget *root;
+
+       int colors[NUM_COLORS];
+};
+
+extern struct wt_context *wt_curctx_;
+#define wt     wt_curctx_
+
+extern void *(*wt_alloc)(size_t sz);
+extern void (*wt_free)(void *p);
+
+void *wt_zalloc(size_t sz);
+
+void wt_gfx_color(int cidx);
+void wt_gfx_fillrect(struct wt_rect *r);
+void wt_gfx_frame(struct wt_rect *r, int style, int basecol);
+void wt_gfx_line(int x0, int y0, int x1, int y1);
+
+#endif /* WTIMPL_H_ */