dirty redraw and SDL framebuffer example
[windtk] / src / windtk.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include "wtimpl.h"
4
5 void *(*wt_alloc)(size_t sz) = malloc;
6 void (*wt_free)(void *p) = free;
7
8 /* one day I may want to allow multiple contexts */
9 static struct wt_context defctx;
10 struct wt_context *wt_curctx_ = &defctx;
11
12 static unsigned int def_colors[] = {
13         0xf0f0f0,       /* font/foreground */
14         0x444444,       /* background */
15         0x555555,       /* highlight */
16         0x333333,       /* shadow */
17         0x403065,       /* inactive frame */
18         0x54349c,       /* inactive frame highlight */
19         0x221e2c,       /* inactive frame shadow */
20         0x8032aa,       /* active frame */
21         0xb14de8,       /* active frame highlight */
22         0x3b2846,       /* active frame shadow */
23         0
24 };
25
26 void *wt_zalloc(size_t sz)
27 {
28         void *p = wt_alloc(sz);
29         if(p) {
30                 memset(p, 0, sz);
31         }
32         return p;
33 }
34
35 void wt_allocator(void *(*allocfunc)(size_t), void (*freefunc)(void *p))
36 {
37         wt_alloc = allocfunc ? allocfunc : malloc;
38         wt_free = freefunc ? freefunc : free;
39 }
40
41
42 int wt_init(int w, int h, struct wt_graphics *gfx)
43 {
44         wt->root = 0;
45         if(!(wt->root = wt_alloc_widget(0))) {
46                 return -1;
47         }
48
49         wt_viewport(0, 0, w, h);
50         wt_graphics(gfx);
51         return 0;
52 }
53
54 void wt_destroy(void)
55 {
56         wt_free_tree(wt->root);
57         wt->root = 0;
58 }
59
60 struct wt_theme *wt_load_theme(const char *path)
61 {
62         return 0;       /* TODO */
63 }
64
65 void wt_unload_theme(struct wt_theme *theme)
66 {
67 }
68
69 static void use_theme(wt_widget *w, struct wt_theme *theme)
70 {
71         int i;
72
73         if(w->use_theme) {
74                 w->use_theme(w, theme);
75         }
76
77         for(i=0; i<w->num_child; i++) {
78                 use_theme(w->child[i], theme);
79         }
80 }
81
82 void wt_use_theme(struct wt_theme *theme)
83 {
84         wt->theme = theme;
85         use_theme(wt->root, theme);
86 }
87
88 void wt_viewport(int x, int y, int w, int h)
89 {
90         wt_rect(&wt->vp, x, y, w, h);
91         wt_move(wt->root, x, y);
92         wt_resize(wt->root, w, h);
93 }
94
95 void wt_graphics(struct wt_graphics *gfx)
96 {
97         int i, r, g, b;
98         wt->gfx = *gfx;
99
100         for(i=0; i<NUM_COLORS; i++) {
101                 r = def_colors[i] >> 16;
102                 g = (def_colors[i] >> 8) & 0xff;
103                 b = def_colors[i] & 0xff;
104                 if((wt->colors[i] = gfx->newcolor(r, g, b)) == -1) {
105                         wt->colors[i] = i ? wt->colors[i - 1] : 0;
106                 }
107         }
108 }
109
110 void wt_inp_key(int key, int press)
111 {
112 }
113
114 void wt_inp_mouse(int bn, int st, int x, int y)
115 {
116 }
117
118 void wt_inp_motion(int x, int y)
119 {
120 }
121
122 void wt_draw_tree(wt_widget *tree)
123 {
124         int i;
125
126         if(tree->draw) {
127                 if(wt->gfx.flags & WT_GFX_NODIRTY) {
128                         tree->draw(tree, &wt->gfx);
129                 } else {
130                         if(tree->dirty) {
131                                 tree->draw(tree, &wt->gfx);
132
133                                 if(!tree->parent || !tree->parent->dirty) {
134                                         /* topmost dirty widget should update rects */
135                                         if(tree->type == WT_TYPE_WINDOW) {
136                                                 struct wt_rect r;
137                                                 calc_window_rect(&r, tree);
138                                                 wt_add_upd_rect(&r);
139                                         } else {
140                                                 wt_add_upd_rect(&tree->rect);
141                                         }
142                                 }
143                         }
144                 }
145         }
146
147         for(i=0; i<tree->num_child; i++) {
148                 wt_draw_tree(tree->child[i]);
149         }
150
151         tree->dirty = 0;
152 }
153
154 void wt_draw(void)
155 {
156         wt->num_upd = 0;
157         wt_draw_tree(wt->root);
158 }
159
160 int wt_num_upd(void)
161 {
162         return wt->num_upd;
163 }
164
165 struct wt_rect *wt_upd_rect(int idx)
166 {
167         if(idx < 0 || idx >= wt->num_upd) {
168                 return 0;
169         }
170         return wt->upd + idx;
171 }
172
173 void wt_add_upd_rect(struct wt_rect *r)
174 {
175         int i;
176         struct wt_rect rect;
177
178         for(i=0; i<wt->num_upd; i++) {
179                 if(wt_rect_overlap(wt->upd + i, r)) {
180                         rect = wt->upd[i];
181                         wt->upd[i] = wt->upd[--wt->num_upd];
182                         wt_rect_union(&rect, r);
183                         wt_add_upd_rect(&rect);
184                         return;
185                 }
186         }
187
188         /* no overlaps found, add it if there is space, or union with existing if not */
189         if(wt->num_upd >= MAX_UPD_RECTS) {
190                 wt_rect_union(wt->upd, r);
191         } else {
192                 wt->upd[wt->num_upd++] = *r;
193         }
194 }
195
196
197 void wt_gfx_color(int cidx)
198 {
199         wt->gfx.color(wt->colors[cidx]);
200 }
201
202 void wt_gfx_fillrect(struct wt_rect *r)
203 {
204         wt->gfx.fillrect(r);
205 }
206
207 void wt_gfx_fillrect4i(int x, int y, int w, int h)
208 {
209         struct wt_rect r;
210         wt_rect(&r, x, y, w, h);
211         wt->gfx.fillrect(&r);
212 }
213
214 void wt_gfx_frame(struct wt_rect *r, int style, int basecol)
215 {
216         if((style & FRM_NOFILL) == 0) {
217                 wt_gfx_color(basecol);
218                 wt_gfx_fillrect(r);
219         }
220         wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 2 : basecol + 1);
221         wt_gfx_fillrect4i(r->x + 1, r->y + r->h - 1, r->w - 2, 1);
222         wt_gfx_fillrect4i(r->x + r->w - 1, r->y, 1, r->h);
223         wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 1 : basecol + 2);
224         wt_gfx_fillrect4i(r->x + 1, r->y, r->w - 2, 1);
225         wt_gfx_fillrect4i(r->x, r->y, 1, r->h);
226 }
227
228 void wt_gfx_line(int x0, int y0, int x1, int y1)
229 {
230         wt->gfx.line(x0, y0, x1, y1);
231 }
232
233 void wt_rect(struct wt_rect *r, int x, int y, int w, int h)
234 {
235         r->x = x;
236         r->y = y;
237         r->w = w;
238         r->h = h;
239 }
240
241 void wt_rect_union(struct wt_rect *a, struct wt_rect *b)
242 {
243         int x1, y1;
244
245         x1 = a->x + a->w;
246         y1 = a->y + a->h;
247
248         if(b->x < a->x) a->x = b->x;
249         if(b->y < a->y) a->y = b->y;
250         if(b->x + b->w > x1) x1 = b->x + b->w;
251         if(b->y + b->h > y1) y1 = b->y + b->h;
252
253         a->w = x1 - a->x;
254         a->h = y1 - a->y;
255 }
256
257 int wt_rect_overlap(struct wt_rect *a, struct wt_rect *b)
258 {
259         if(a->x > b->x + b->w) return 0;
260         if(b->x > a->x + a->w) return 0;
261         if(a->y > b->y + b->h) return 0;
262         if(b->y > a->x + a->h) return 0;
263         return 1;
264 }