dirty redraw and SDL framebuffer example master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 23 Nov 2021 05:34:15 +0000 (07:34 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 23 Nov 2021 05:34:40 +0000 (07:34 +0200)
.gitignore
Makefile
example.c [deleted file]
example_gl.c [new file with mode: 0644]
example_sdl.c [new file with mode: 0644]
src/widget.c
src/widget.h
src/window.c
src/windtk.c
src/windtk.h
src/wtimpl.h

index 2a4e0bf..2865d40 100644 (file)
@@ -1,4 +1,5 @@
 *.o
 *.d
 *.swp
-example
+example_gl
+example_sdl
index adce8a2..289aabf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,24 @@
-src = $(wildcard src/*.c) example.c
+src = $(wildcard src/*.c)
 obj = $(src:.c=.o)
-dep = $(src:.c=.d)
-bin = example
+dep = $(src:.c=.d) example_gl.d example_sdl.d
 
 CFLAGS = -pedantic -Wall -g -Isrc -MMD
-LDFLAGS = -lGL -lglut
 
-$(bin): $(obj)
-       $(CC) -o $@ $(obj) $(LDFLAGS)
+.PHONY: all
+all: example_gl example_sdl
+
+example_gl: $(obj) example_gl.o
+       $(CC) -o $@ $^ $(LDFLAGS) -lGL -lglut
+
+example_sdl: $(obj) example_sdl.o
+       $(CC) -o $@ $^ $(LDFLAGS) -lSDL
 
 -include $(dep)
 
 .PHONY: clean
 clean:
-       rm -f $(obj)
+       rm -f $(obj) *.o example_gl example_sdl
+
+.PHONY: cleandep
+cleandep:
+       rm -f $(dep) *.d
diff --git a/example.c b/example.c
deleted file mode 100644 (file)
index 4ff5bdc..0000000
--- a/example.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#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);
-
-       glClearColor(0.6, 0.6, 0.6, 1);
-
-       if(wt_init(800, 600, &gfx)) {
-               return 1;
-       }
-       wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200);
-
-       glutMainLoop();
-       return 0;
-}
-
-static void display(void)
-{
-       glClear(GL_COLOR_BUFFER_BIT);
-
-       wt_draw();
-
-       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/example_gl.c b/example_gl.c
new file mode 100644 (file)
index 0000000..17ed974
--- /dev/null
@@ -0,0 +1,135 @@
+#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 = {
+       WT_GFX_NODIRTY,
+       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);
+
+       glClearColor(0.6, 0.6, 0.6, 1);
+
+       if(wt_init(800, 600, &gfx) == -1) {
+               return 1;
+       }
+       wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200);
+
+       glutMainLoop();
+       return 0;
+}
+
+static void display(void)
+{
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       wt_draw();
+
+       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 unsigned char colors[32][3];
+static int maxcol;
+
+static int gfx_newcol(int r, int g, int b)
+{
+       int i;
+
+       for(i=0; i<maxcol; i++) {
+               if(colors[i][0] == r && colors[i][1] == g && colors[i][2] == b) {
+                       return i;
+               }
+       }
+
+       if(maxcol >= 32) return -1;
+
+       colors[maxcol][0] = r;
+       colors[maxcol][1] = g;
+       colors[maxcol][2] = b;
+       return maxcol++;
+}
+
+static void gfx_color(int c)
+{
+       glColor3ubv(colors[c]);
+}
+
+static void gfx_fillrect(struct wt_rect *r)
+{
+       glBegin(GL_QUADS);
+       glVertex2f(r->x, r->y);
+       glVertex2f(r->x + r->w, r->y);
+       glVertex2f(r->x + r->w, r->y + r->h);
+       glVertex2f(r->x, r->y + r->h);
+       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/example_sdl.c b/example_sdl.c
new file mode 100644 (file)
index 0000000..deb7fce
--- /dev/null
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL/SDL.h>
+#include "windtk.h"
+
+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 = {
+       0,
+       gfx_newcol, gfx_color,
+       gfx_fillrect,
+       gfx_line
+};
+
+static SDL_Surface *fbsurf;
+static SDL_PixelFormat *pfmt;
+static int fb_width = 800, fb_height = 600;
+static uint32_t *fb;
+
+int main(void)
+{
+       int i, num_upd;
+       struct wt_rect *rect;
+       SDL_Event ev;
+
+       if(SDL_Init(SDL_INIT_VIDEO) == -1) {
+               fprintf(stderr, "failed to initialize SDL\n");
+               return 1;
+       }
+
+       if(!(fbsurf = SDL_SetVideoMode(fb_width, fb_height, 32, SDL_SWSURFACE | SDL_RESIZABLE))) {
+               fprintf(stderr, "failed to set video mode\n");
+               SDL_Quit();
+               return 1;
+       }
+       pfmt = fbsurf->format;
+
+       SDL_FillRect(fbsurf, 0, 0);
+
+       if(wt_init(fb_width, fb_height, &gfx) == -1) {
+               return 1;
+       }
+       wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200);
+
+       while(SDL_WaitEvent(&ev)) {
+               switch(ev.type) {
+               case SDL_QUIT:
+                       goto end;
+
+               case SDL_KEYDOWN:
+               case SDL_KEYUP:
+                       if(ev.key.keysym.sym == SDLK_ESCAPE) {
+                               goto end;
+                       }
+                       wt_inp_key(ev.key.keysym.sym, ev.key.state == SDL_PRESSED);
+                       break;
+
+               case SDL_MOUSEBUTTONDOWN:
+               case SDL_MOUSEBUTTONUP:
+                       wt_inp_mouse(ev.button.button - SDL_BUTTON_LEFT, ev.button.state == SDL_PRESSED,
+                                       ev.button.x, ev.button.y);
+                       break;
+
+               case SDL_MOUSEMOTION:
+                       wt_inp_motion(ev.motion.x, ev.motion.y);
+                       break;
+
+               case SDL_VIDEORESIZE:
+                       fb_width = ev.resize.w;
+                       fb_height = ev.resize.h;
+                       wt_viewport(0, 0, ev.resize.w, ev.resize.h);
+                       break;
+
+               default:
+                       break;
+               }
+
+               if(SDL_MUSTLOCK(fbsurf)) {
+                       SDL_LockSurface(fbsurf);
+               }
+               fb = fbsurf->pixels;
+               wt_draw();
+               if(SDL_MUSTLOCK(fbsurf)) {
+                       SDL_UnlockSurface(fbsurf);
+               }
+
+               num_upd = wt_num_upd();
+               for(i=0; i<num_upd; i++) {
+                       rect = wt_upd_rect(i);
+                       SDL_UpdateRect(fbsurf, rect->x, rect->y, rect->w, rect->h);
+               }
+       }
+
+end:
+       wt_destroy();
+       SDL_Quit();
+       return 0;
+}
+
+/* ------ graphics callbacks -------- */
+static uint32_t colors[32];
+static int maxcol, curcol;
+
+static int gfx_newcol(int r, int g, int b)
+{
+       int i;
+       uint32_t pcol;
+
+       pcol = ((r >> pfmt->Rloss) << pfmt->Rshift) & pfmt->Rmask;
+       pcol |= ((g >> pfmt->Gloss) << pfmt->Gshift) & pfmt->Gmask;
+       pcol |= ((b >> pfmt->Bloss) << pfmt->Bshift) & pfmt->Bmask;
+
+       for(i=0; i<maxcol; i++) {
+               if(colors[i] == pcol) {
+                       return i;
+               }
+       }
+
+       if(maxcol >= 32) return -1;
+
+       colors[maxcol] = pcol;
+       return maxcol++;
+}
+
+static void gfx_color(int c)
+{
+       curcol = c;
+}
+
+static void gfx_fillrect(struct wt_rect *r)
+{
+       int i, j, x, y, w, h;
+       uint32_t pcol = colors[curcol];
+       uint32_t *fbptr;
+
+       w = r->w;
+       h = r->h;
+       x = r->x;
+       y = r->y;
+
+       if(x < 0) {
+               w += x;
+               x = 0;
+       }
+       if(y < 0) {
+               h += y;
+               y = 0;
+       }
+       if(x + w >= fb_width) {
+               w = fb_width - x;
+       }
+       if(y + h >= fb_height) {
+               h = fb_height - y;
+       }
+
+       fbptr = fb + y * (fbsurf->pitch >> 2) + x;
+       for(i=0; i<h; i++) {
+               for(j=0; j<w; j++) {
+                       fbptr[j] = pcol;
+               }
+               fbptr += fbsurf->pitch >> 2;
+       }
+}
+
+static void gfx_line(int x0, int y0, int x1, int y1)
+{
+}
index 96be755..02c3ff0 100644 (file)
@@ -9,6 +9,7 @@ wt_widget *wt_alloc_widget(wt_widget *par)
                return 0;
        }
        w->type = WT_TYPE_WIDGET;
+       w->dirty = 1;
 
        if(!par) par = wt->root;
        wt_add_child(par, w);
@@ -36,6 +37,17 @@ void wt_free_tree(wt_widget *tree)
        wt_free_widget(tree);
 }
 
+void wt_dirty_widget(wt_widget *w)
+{
+       int i;
+
+       w->dirty = 1;
+
+       for(i=0; i<w->num_child; i++) {
+               wt_dirty_widget(w->child[i]);
+       }
+}
+
 int wt_type(wt_widget *w)
 {
        return w->type;
@@ -156,8 +168,8 @@ void wt_move(wt_widget *w, int x, int y)
 
 void wt_resize(wt_widget *w, int x, int y)
 {
-       w->rect.width = x;
-       w->rect.height = y;
+       w->rect.w = x;
+       w->rect.h = y;
        /* TODO: invalidate something */
 }
 
@@ -170,15 +182,15 @@ int *wt_position(wt_widget *w, int *xret, int *yret)
 
 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;
+       if(xret) *xret = w->rect.w;
+       if(yret) *yret = w->rect.h;
+       return &w->rect.w;
 }
 
 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;
+       return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.w &&
+               y < w->rect.y + w->rect.h;
 }
 
 wt_widget *wt_widget_at(int x, int y)
index c174f43..e7c44dc 100644 (file)
@@ -16,6 +16,8 @@ struct wt_widget {
        wt_callback_func cb[WT_NUM_CALLBACKS];
        void *cbcls[WT_NUM_CALLBACKS];
 
+       int dirty;      /* redraw pending */
+
        wt_draw_func draw;
        void (*click)(struct wt_widget *w);
        void (*keypress)(struct wt_widget *w, int key);
index cd39284..9925db4 100644 (file)
@@ -26,6 +26,14 @@ wt_widget *wt_window(wt_widget *par, const char *title, int style, int x, int y,
 #define TBARTHICK      12      /* TODO: base it on font metrics */
 #define TBAROFFS       (TBARTHICK + FRMBEVEL * 2)
 
+void calc_window_rect(struct wt_rect *r, wt_widget *w)
+{
+       r->x = w->rect.x - FRMOFFS;
+       r->y = w->rect.y - TBAROFFS - FRMOFFS;
+       r->w = w->rect.w + FRMOFFS * 2;
+       r->h = w->rect.h + TBAROFFS + FRMOFFS * 2;
+}
+
 static void draw_win(wt_widget *w, struct wt_graphics *gfx)
 {
        struct wt_rect fr, tmprect;
@@ -34,10 +42,7 @@ static void draw_win(wt_widget *w, struct wt_graphics *gfx)
        wt_gfx_color(COL_BG);
        wt_gfx_fillrect(&w->rect);
 
-       fr.x = w->rect.x - FRMOFFS;
-       fr.y = w->rect.y - TBAROFFS - FRMOFFS;
-       fr.width = w->rect.width + FRMOFFS * 2;
-       fr.height = w->rect.height + TBAROFFS + FRMOFFS * 2;
+       calc_window_rect(&fr, w);
 
        wt_gfx_frame(&fr, FRM_OUT | FRM_NOFILL, frmcol);        /* outer bevel */
 
@@ -46,35 +51,35 @@ static void draw_win(wt_widget *w, struct wt_graphics *gfx)
 
        fr.x += FRMBEVEL;
        fr.y += FRMBEVEL;
-       fr.width -= FRMBEVEL * 2;
-       fr.height -= FRMBEVEL * 2;
+       fr.w -= FRMBEVEL * 2;
+       fr.h -= FRMBEVEL * 2;
 
        tmprect = fr;
-       tmprect.width = FRMTHICK;
+       tmprect.w = FRMTHICK;
        wt_gfx_fillrect(&tmprect);      /* left bar */
-       tmprect.x += fr.width - FRMTHICK;
+       tmprect.x += fr.w - FRMTHICK;
        wt_gfx_fillrect(&tmprect);      /* right bar */
 
        tmprect = fr;
-       tmprect.height = FRMTHICK;
+       tmprect.h = FRMTHICK;
        tmprect.x += FRMTHICK;
-       tmprect.width -= FRMTHICK * 2;
+       tmprect.w -= FRMTHICK * 2;
        wt_gfx_fillrect(&tmprect);      /* top bar */
-       tmprect.y += fr.height - FRMTHICK;
+       tmprect.y += fr.h - FRMTHICK;
        wt_gfx_fillrect(&tmprect);      /* bottom bar */
 
        /* inner bevel */
        fr.x += FRMTHICK;
        fr.y += FRMTHICK;
-       fr.width -= FRMTHICK * 2;
-       fr.height -= FRMTHICK * 2;
+       fr.w -= FRMTHICK * 2;
+       fr.h -= FRMTHICK * 2;
        wt_gfx_frame(&fr, FRM_IN | FRM_NOFILL, frmcol);
 
        /* titlebar */
        fr.x = w->rect.x;
-       fr.width = w->rect.width;
+       fr.w = w->rect.w;
        fr.y += FRMBEVEL;
-       fr.height = TBARTHICK + FRMBEVEL * 2;
+       fr.h = TBARTHICK + FRMBEVEL * 2;
        wt_gfx_frame(&fr, FRM_OUT, frmcol);
 }
 
index c34dc42..69ad9fa 100644 (file)
@@ -124,19 +124,76 @@ void wt_draw_tree(wt_widget *tree)
        int i;
 
        if(tree->draw) {
-               tree->draw(tree, &wt->gfx);
+               if(wt->gfx.flags & WT_GFX_NODIRTY) {
+                       tree->draw(tree, &wt->gfx);
+               } else {
+                       if(tree->dirty) {
+                               tree->draw(tree, &wt->gfx);
+
+                               if(!tree->parent || !tree->parent->dirty) {
+                                       /* topmost dirty widget should update rects */
+                                       if(tree->type == WT_TYPE_WINDOW) {
+                                               struct wt_rect r;
+                                               calc_window_rect(&r, tree);
+                                               wt_add_upd_rect(&r);
+                                       } else {
+                                               wt_add_upd_rect(&tree->rect);
+                                       }
+                               }
+                       }
+               }
        }
 
        for(i=0; i<tree->num_child; i++) {
                wt_draw_tree(tree->child[i]);
        }
+
+       tree->dirty = 0;
 }
 
 void wt_draw(void)
 {
+       wt->num_upd = 0;
        wt_draw_tree(wt->root);
 }
 
+int wt_num_upd(void)
+{
+       return wt->num_upd;
+}
+
+struct wt_rect *wt_upd_rect(int idx)
+{
+       if(idx < 0 || idx >= wt->num_upd) {
+               return 0;
+       }
+       return wt->upd + idx;
+}
+
+void wt_add_upd_rect(struct wt_rect *r)
+{
+       int i;
+       struct wt_rect rect;
+
+       for(i=0; i<wt->num_upd; i++) {
+               if(wt_rect_overlap(wt->upd + i, r)) {
+                       rect = wt->upd[i];
+                       wt->upd[i] = wt->upd[--wt->num_upd];
+                       wt_rect_union(&rect, r);
+                       wt_add_upd_rect(&rect);
+                       return;
+               }
+       }
+
+       /* no overlaps found, add it if there is space, or union with existing if not */
+       if(wt->num_upd >= MAX_UPD_RECTS) {
+               wt_rect_union(wt->upd, r);
+       } else {
+               wt->upd[wt->num_upd++] = *r;
+       }
+}
+
+
 void wt_gfx_color(int cidx)
 {
        wt->gfx.color(wt->colors[cidx]);
@@ -161,11 +218,11 @@ void wt_gfx_frame(struct wt_rect *r, int style, int basecol)
                wt_gfx_fillrect(r);
        }
        wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 2 : basecol + 1);
-       wt_gfx_fillrect4i(r->x + 1, r->y + r->height - 1, r->width - 2, 1);
-       wt_gfx_fillrect4i(r->x + r->width - 1, r->y, 1, r->height);
+       wt_gfx_fillrect4i(r->x + 1, r->y + r->h - 1, r->w - 2, 1);
+       wt_gfx_fillrect4i(r->x + r->w - 1, r->y, 1, r->h);
        wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 1 : basecol + 2);
-       wt_gfx_fillrect4i(r->x + 1, r->y, r->width - 2, 1);
-       wt_gfx_fillrect4i(r->x, r->y, 1, r->height);
+       wt_gfx_fillrect4i(r->x + 1, r->y, r->w - 2, 1);
+       wt_gfx_fillrect4i(r->x, r->y, 1, r->h);
 }
 
 void wt_gfx_line(int x0, int y0, int x1, int y1)
@@ -177,6 +234,31 @@ void wt_rect(struct wt_rect *r, int x, int y, int w, int h)
 {
        r->x = x;
        r->y = y;
-       r->width = w;
-       r->height = h;
+       r->w = w;
+       r->h = h;
+}
+
+void wt_rect_union(struct wt_rect *a, struct wt_rect *b)
+{
+       int x1, y1;
+
+       x1 = a->x + a->w;
+       y1 = a->y + a->h;
+
+       if(b->x < a->x) a->x = b->x;
+       if(b->y < a->y) a->y = b->y;
+       if(b->x + b->w > x1) x1 = b->x + b->w;
+       if(b->y + b->h > y1) y1 = b->y + b->h;
+
+       a->w = x1 - a->x;
+       a->h = y1 - a->y;
+}
+
+int wt_rect_overlap(struct wt_rect *a, struct wt_rect *b)
+{
+       if(a->x > b->x + b->w) return 0;
+       if(b->x > a->x + a->w) return 0;
+       if(a->y > b->y + b->h) return 0;
+       if(b->y > a->x + a->h) return 0;
+       return 1;
 }
index 0435e6f..996d473 100644 (file)
@@ -49,10 +49,18 @@ struct wt_image {
 };
 
 struct wt_rect {
-       int x, y, width, height;
+       int x, y, w, h;
+};
+
+/* graphics flags */
+enum {
+       WT_GFX_RGB              = 1,    /* RGB mode, calls newcolor to set current, not to allocate */
+       WT_GFX_NODIRTY  = 2             /* don't use dirty rects, always redraw completely */
 };
 
 struct wt_graphics {
+       unsigned int flags;
+
        int (*newcolor)(int r, int g, int b);
        void (*color)(int c);
 
@@ -100,10 +108,17 @@ void wt_inp_motion(int x, int y);
 
 void wt_draw(void);
 
+/* screen regions updated by the last wt_draw */
+int wt_num_upd(void);
+struct wt_rect *wt_upd_rect(int idx);
+void wt_add_upd_rect(struct wt_rect *r);
+
 wt_widget *wt_alloc_widget(wt_widget *par);
 void wt_free_widget(wt_widget *w);
 void wt_free_tree(wt_widget *tree);
 
+void wt_dirty_widget(wt_widget *w);            /* propagates to children */
+
 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);
@@ -154,5 +169,7 @@ int wt_isenabled(wt_widget *w);
 void wt_callback(wt_widget *w, int type, wt_callback_func func, void *cls);
 
 void wt_rect(struct wt_rect *r, int x, int y, int w, int h);
+void wt_rect_union(struct wt_rect *a, struct wt_rect *b);
+int wt_rect_overlap(struct wt_rect *a, struct wt_rect *b);
 
 #endif /* WINDTK_H_ */
index 76e51f1..d0c2ea4 100644 (file)
@@ -23,6 +23,8 @@ enum {
 enum { FRM_OUT, FRM_IN, FRM_NOFILL = 0x8000 };
 #define FRMSTYLE(x)    ((x) & 0xff)
 
+#define MAX_UPD_RECTS  16
+
 struct wt_context {
        struct wt_graphics gfx;
        struct wt_rect vp;
@@ -32,6 +34,9 @@ struct wt_context {
        int colors[NUM_COLORS];
 
        wt_widget *focuswin;
+
+       struct wt_rect upd[MAX_UPD_RECTS];
+       int num_upd;
 };
 
 extern struct wt_context *wt_curctx_;
@@ -47,4 +52,6 @@ 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);
 
+void calc_window_rect(struct wt_rect *r, wt_widget *w);
+
 #endif /* WTIMPL_H_ */