From: John Tsiombikas Date: Mon, 22 Nov 2021 21:10:18 +0000 (+0200) Subject: initial commit X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=windtk;a=commitdiff_plain;h=932050b6d47ae674793437d798ccd16894c01e13 initial commit --- 932050b6d47ae674793437d798ccd16894c01e13 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a4e0bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.d +*.swp +example diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..2d13dc5 --- /dev/null +++ b/example.c @@ -0,0 +1,120 @@ +#include +#include +#include +#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 index 0000000..07643db --- /dev/null +++ b/src/widget.c @@ -0,0 +1,230 @@ +#include +#include +#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; inum_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; inum_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; inum_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 index 0000000..0a978cf --- /dev/null +++ b/src/widget.h @@ -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 index 0000000..a103ed4 --- /dev/null +++ b/src/window.c @@ -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 index 0000000..1e4de86 --- /dev/null +++ b/src/windtk.c @@ -0,0 +1,126 @@ +#include +#include +#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> 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 index 0000000..56ca8a6 --- /dev/null +++ b/src/windtk.h @@ -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 index 0000000..d9f3410 --- /dev/null +++ b/src/wtimpl.h @@ -0,0 +1,46 @@ +#ifndef WTIMPL_H_ +#define WTIMPL_H_ + +#include +#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_ */