start by copying windtk and dropping dirty rects and indexed colors
[anigui] / src / widget.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include "agimpl.h"
4
5 ag_widget *ag_alloc_widget(ag_widget *par)
6 {
7         ag_widget *w;
8         if(!(w = ag_zalloc(sizeof *w))) {
9                 return 0;
10         }
11         w->type = AG_TYPE_WIDGET;
12         w->dirty = 1;
13
14         if(!par) par = ag->root;
15         ag_add_child(par, w);
16         return w;
17 }
18
19 void ag_free_widget(ag_widget *w)
20 {
21         if(w) {
22                 ag_free(w->text);
23                 ag_free(w->child);
24                 ag_free(w);
25         }
26 }
27
28 void ag_free_tree(ag_widget *tree)
29 {
30         int i;
31
32         if(!tree) return;
33
34         for(i=0; i<tree->num_child; i++) {
35                 ag_free_tree(tree->child[i]);
36         }
37         ag_free_widget(tree);
38 }
39
40 void ag_dirty_widget(ag_widget *w)
41 {
42         int i;
43
44         w->dirty = 1;
45
46         for(i=0; i<w->num_child; i++) {
47                 ag_dirty_widget(w->child[i]);
48         }
49 }
50
51 int ag_type(ag_widget *w)
52 {
53         return w->type;
54 }
55
56 int ag_set_text(ag_widget *w, const char *text)
57 {
58         char *s;
59
60         if(!(s = ag_alloc(strlen(text) + 1))) {
61                 return -1;
62         }
63         strcpy(s, text);
64         ag_free(w->text);
65         w->text = s;
66         return 0;
67 }
68
69 const char *ag_text(ag_widget *w)
70 {
71         return w->text;
72 }
73
74 static int find_child(ag_widget *w, ag_widget *c)
75 {
76         int i;
77         for(i=0; i<w->num_child; i++) {
78                 if(w->child[i] == c) {
79                         return i;
80                 }
81         }
82         return -1;
83 }
84
85 int ag_add_child(ag_widget *w, ag_widget *c)
86 {
87         if(!w || !c) return -1;
88
89         if(find_child(w, c) != -1) {
90                 return 0;
91         }
92         if(c->parent) {
93                 ag_remove_child(c->parent, c);
94         }
95
96         if(w->num_child >= w->max_child) {
97                 void *newarr;
98                 int newsz = w->max_child ? w->max_child << 1 : 8;
99                 if(!(newarr = ag_alloc(newsz * sizeof *w->child))) {
100                         return -1;
101                 }
102                 memcpy(newarr, w->child, w->num_child * sizeof *w->child);
103                 ag_free(w->child);
104                 w->child = newarr;
105                 w->max_child = newsz;
106         }
107
108         w->child[w->num_child++] = c;
109         return 0;
110 }
111
112 int ag_remove_child(ag_widget *w, ag_widget *c)
113 {
114         int idx;
115
116         if(!w->num_child || (idx = find_child(w, c)) == -1) {
117                 return -1;
118         }
119         w->child[idx] = w->child[--w->num_child];
120
121         if(w->max_child > 8 && w->num_child < w->max_child / 3) {
122                 void *newarr;
123                 int newsz = w->max_child >> 1;
124                 if(!(newarr = ag_alloc(newsz * sizeof *w->child))) {
125                         return -1;
126                 }
127                 memcpy(newarr, w->child, w->num_child * sizeof *w->child);
128                 ag_free(w->child);
129                 w->child = newarr;
130                 w->max_child = newsz;
131         }
132         return 0;
133 }
134
135 ag_widget *ag_parent(ag_widget *w)
136 {
137         return w->parent;
138 }
139
140 ag_widget *ag_widget_window(ag_widget *w)
141 {
142         ag_widget *par = w;
143         while(par && par->type != AG_TYPE_WINDOW) {
144                 par = par->parent;
145         }
146         return par;
147 }
148
149 int ag_child_count(ag_widget *w)
150 {
151         return w->num_child;
152 }
153
154 ag_widget *ag_child(ag_widget *w, int idx)
155 {
156         if(idx < 0 || idx >= w->num_child) {
157                 return 0;
158         }
159         return w->child[idx];
160 }
161
162 void ag_move(ag_widget *w, int x, int y)
163 {
164         w->rect.x = x;
165         w->rect.y = y;
166         /* TODO: invalidate something */
167 }
168
169 void ag_resize(ag_widget *w, int x, int y)
170 {
171         w->rect.w = x;
172         w->rect.h = y;
173         /* TODO: invalidate something */
174 }
175
176 int *ag_position(ag_widget *w, int *xret, int *yret)
177 {
178         if(xret) *xret = w->rect.x;
179         if(yret) *yret = w->rect.y;
180         return &w->rect.x;
181 }
182
183 int *ag_size(ag_widget *w, int *xret, int *yret)
184 {
185         if(xret) *xret = w->rect.w;
186         if(yret) *yret = w->rect.h;
187         return &w->rect.w;
188 }
189
190 int ag_hittest(ag_widget *w, int x, int y)
191 {
192         return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.w &&
193                 y < w->rect.y + w->rect.h;
194 }
195
196 ag_widget *ag_widget_at(int x, int y)
197 {
198         int i;
199         ag_widget *w, *c;
200
201         if(!ag_hittest(ag->root, x, y)) {
202                 return 0;
203         }
204
205         w = 0;
206         c = ag->root;
207         do {
208                 w = c;
209                 c = 0;
210                 for(i=0; i<w->num_child; i++) {
211                         if(ag_hittest(w->child[i], x, y)) {
212                                 c = w->child[i];
213                                 break;
214                         }
215                 }
216         } while(c);
217
218         return w;
219 }
220
221 /*
222 void ag_layout(ag_widget *w, int layout);
223 void ag_padding(ag_widget *w, int pad);
224 void ag_relayout(ag_widget *w);
225
226 void ag_focus(ag_widget *w);
227 void ag_unfocus(ag_widget *w);
228 int ag_isfocused(ag_widget *w);
229
230 void ag_hover(ag_widget *w);
231 void ag_unhover(ag_widget *w);
232 int ag_ishover(ag_widget *w);
233
234 void ag_enable(ag_widget *w);
235 void ag_disable(ag_widget *w);
236 int ag_isenabled(ag_widget *w);
237 */
238
239 void ag_callback(ag_widget *w, int type, ag_callback_func func, void *cls)
240 {
241         w->cb[type] = func;
242         w->cbcls[type] = cls;
243 }