1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2005 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include "ui2_includes.h"
13 #include "ui2_typedefs.h"
14 #include "ui2_widget.h"
15
16 #include "ui2_display.h"
17 #include "ui2_skin.h"
18 #include "ui_pixbuf_ops.h"
19
20
21 /*
22 *-------------------------------
23 * new / free
24 *-------------------------------
25 */
26
ui_widget_free(WidgetData * wd)27 void ui_widget_free(WidgetData *wd)
28 {
29 GList *work;
30
31 if (wd->od && wd->od->func_free) wd->od->func_free(wd->widget);
32
33 g_free(wd->key);
34 g_free(wd->text_id);
35
36 work = wd->data_list;
37 while(work)
38 {
39 g_free(work->data);
40 work = work->next;
41 }
42 g_list_free(wd->data_list);
43
44 g_free(wd);
45 }
46
ui_widget_new(const gchar * key,const gchar * text_id,WidgetType type,gpointer widget)47 WidgetData *ui_widget_new(const gchar *key, const gchar *text_id, WidgetType type, gpointer widget)
48 {
49 WidgetData *wd;
50
51 wd = g_new0(WidgetData, 1);
52 wd->type = type;
53 wd->key = g_strdup(key);
54 wd->text_id = g_strdup(text_id);
55 wd->widget = widget;
56 wd->data_list = NULL;
57
58 wd->od = ui_widget_object_by_type(type);
59 if (!wd->od)
60 {
61 printf("warning: unknown ui widget type %d\n", type);
62 }
63
64 wd->hidden = FALSE;
65 wd->in_bounds = TRUE;
66
67 wd->anchor_right = FALSE;
68 wd->anchor_bottom = FALSE;
69
70 wd->exclusive = FALSE;
71
72 return wd;
73 }
74
75 /*
76 *-------------------------------
77 * widget ui funcs
78 *-------------------------------
79 */
80
ui_widget_motion(UIData * ui,WidgetData * wd,gint x,gint y)81 void ui_widget_motion(UIData *ui, WidgetData *wd, gint x, gint y)
82 {
83 if (wd->hidden || !wd->in_bounds) return;
84
85 if (wd->od && wd->od->func_motion)
86 {
87 wd->od->func_motion(wd->widget, wd->key, x, y, ui->skin->pixbuf, ui);
88 }
89 }
90
ui_widget_press(UIData * ui,WidgetData * wd,gint x,gint y)91 gint ui_widget_press(UIData *ui, WidgetData *wd, gint x, gint y)
92 {
93 if (wd->hidden || !wd->in_bounds) return FALSE;
94
95 if (wd->od && wd->od->func_press)
96 {
97 return wd->od->func_press(wd->widget, wd->key, x, y, ui->skin->pixbuf, ui);
98 }
99
100 return FALSE;
101 }
102
ui_widget_release(UIData * ui,WidgetData * wd,gint x,gint y)103 void ui_widget_release(UIData *ui, WidgetData *wd, gint x, gint y)
104 {
105 if (wd->hidden || !wd->in_bounds) return;
106
107 if (wd->od && wd->od->func_release)
108 {
109 wd->od->func_release(wd->widget, wd->key, x, y, ui->skin->pixbuf, ui);
110 }
111 }
112
ui_widget_draw(UIData * ui,WidgetData * wd,gint update,gint force)113 void ui_widget_draw(UIData *ui, WidgetData *wd, gint update, gint force)
114 {
115 if (wd->hidden || !wd->in_bounds) return;
116
117 if (wd->od && wd->od->func_draw)
118 {
119 wd->od->func_draw(wd->widget, wd->key, update, force, ui->skin->pixbuf, ui);
120 }
121 }
122
ui_widget_reset(UIData * ui,WidgetData * wd)123 void ui_widget_reset(UIData *ui, WidgetData *wd)
124 {
125 if (wd->hidden || !wd->in_bounds) return;
126
127 if (wd->od && wd->od->func_reset)
128 {
129 wd->od->func_reset(wd->widget, wd->key, ui->skin->pixbuf, ui);
130 }
131 }
132
ui_widget_sync_back(UIData * ui,WidgetData * wd)133 void ui_widget_sync_back(UIData *ui, WidgetData *wd)
134 {
135 /* even hidden items sync their back if in bounds */
136 if (!wd->in_bounds) return;
137
138 if (wd->od && wd->od->func_back)
139 {
140 wd->od->func_back(wd->widget, ui->skin->overlay);
141 }
142 }
143
ui_widget_hide(UIData * ui,WidgetData * wd)144 void ui_widget_hide(UIData *ui, WidgetData *wd)
145 {
146 gint x, y, w, h;
147
148 if (wd->hidden) return;
149
150 wd->hidden = TRUE;
151 if (ui_widget_get_geometry(wd, &x, &y, &w, &h))
152 {
153 ui_display_redraw_area(ui, x, y, w, h, FALSE);
154 }
155 }
156
ui_widget_show(UIData * ui,WidgetData * wd)157 void ui_widget_show(UIData *ui, WidgetData *wd)
158 {
159 if (!wd->hidden) return;
160
161 wd->hidden = FALSE;
162 ui_widget_draw(ui, wd, TRUE, TRUE);
163 }
164
165 /*
166 *-------------------------------
167 * widget focus funcs
168 *-------------------------------
169 */
170
ui_widget_focus_draw(UIData * ui,WidgetData * wd,gint x,gint y,gint w,gint h)171 gint ui_widget_focus_draw(UIData *ui, WidgetData *wd, gint x, gint y, gint w, gint h)
172 {
173 if (wd->od && wd->od->func_focus_draw)
174 {
175 return wd->od->func_focus_draw(wd->widget, wd->key, x, y, w, h, ui->skin->pixbuf, ui);
176 }
177
178 return FALSE;
179 }
180
ui_widget_focus_key_event(UIData * ui,WidgetData * wd,GdkEventKey * event)181 gint ui_widget_focus_key_event(UIData *ui, WidgetData *wd, GdkEventKey *event)
182 {
183 if (wd->od && wd->od->func_focus_key_event)
184 {
185 return wd->od->func_focus_key_event(wd->widget, wd->key, event, ui->skin->pixbuf, ui);
186 }
187
188 return FALSE;
189 }
190
ui_widget_can_focus(WidgetData * wd)191 gint ui_widget_can_focus(WidgetData *wd)
192 {
193 return (wd->od && !wd->hidden && wd->in_bounds && wd->od->func_focus_key_event);
194 }
195
196 /*
197 *-------------------------------
198 * widget misc funcs
199 *-------------------------------
200 */
201
ui_widget_for_each_key_one(UIData * ui,const gchar * key,WidgetType type,void (* func)(WidgetData * wd,gpointer data,UIData * ui),gpointer data)202 gint ui_widget_for_each_key_one(UIData *ui, const gchar *key, WidgetType type,
203 void (*func)(WidgetData *wd, gpointer data, UIData *ui),
204 gpointer data)
205 {
206 gint count = 0;
207 GList *work;
208
209 if (!func || !ui->skin) return 0;
210
211 work = ui->skin->widget_list;
212 while (work)
213 {
214 WidgetData *wd = work->data;
215
216 if (wd->type == type && strcmp(key, wd->key) == 0)
217 {
218 func(wd, data, ui);
219 count++;
220 }
221
222 work = work->next;
223 }
224
225 return count;
226 }
227
ui_widget_for_each_key(UIData * ui,const gchar * key,WidgetType type,void (* func)(WidgetData * wd,gpointer data,UIData * ui),gpointer data)228 gint ui_widget_for_each_key(UIData *ui, const gchar *key, WidgetType type,
229 void (*func)(WidgetData *wd, gpointer data, UIData *ui),
230 gpointer data)
231 {
232 gint count;
233 UIData *parent;
234 GList *work;
235
236 if (ui->parent)
237 {
238 parent = ui->parent;
239 }
240 else
241 {
242 parent = ui;
243 }
244
245 count = ui_widget_for_each_key_one(parent, key, type, func, data);
246
247 work = parent->children;
248 while (work)
249 {
250 UIData *child;
251
252 child = work->data;
253 work = work->next;
254
255 count += ui_widget_for_each_key_one(child, key, type, func, data);
256 }
257
258 /* editor updates */
259 if (parent->edit)
260 {
261 ui_widget_for_each_key_one(parent->edit, key, type, func, data);
262 }
263
264 return count;
265 }
266
ui_widget_hide_by_key_cb(WidgetData * wd,gpointer data,UIData * ui)267 static void ui_widget_hide_by_key_cb(WidgetData *wd, gpointer data, UIData *ui)
268 {
269 ui_widget_hide(ui, wd);
270 }
271
ui_widget_hide_by_key(UIData * ui,const gchar * key,WidgetType type)272 void ui_widget_hide_by_key(UIData *ui, const gchar *key, WidgetType type)
273 {
274 if (!ui || !key) return;
275
276 ui_widget_for_each_key(ui, key, type, ui_widget_hide_by_key_cb, NULL);
277 }
278
ui_widget_show_by_key_cb(WidgetData * wd,gpointer data,UIData * ui)279 static void ui_widget_show_by_key_cb(WidgetData *wd, gpointer data, UIData *ui)
280 {
281 ui_widget_show(ui, wd);
282 }
283
ui_widget_show_by_key(UIData * ui,const gchar * key,WidgetType type)284 void ui_widget_show_by_key(UIData *ui, const gchar *key, WidgetType type)
285 {
286 if (!ui || !key) return;
287
288 ui_widget_for_each_key(ui, key, type, ui_widget_show_by_key_cb, NULL);
289 }
290
291 /*
292 *-------------------------------
293 * widget ui func utils
294 *-------------------------------
295 */
296
ui_widget_get_geometry(WidgetData * wd,gint * x,gint * y,gint * w,gint * h)297 gint ui_widget_get_geometry(WidgetData *wd, gint *x, gint *y, gint *w, gint *h)
298 {
299 gint nx, ny, nw, nh;
300
301 if (!wd->od || !wd->od->func_get_geometry) return FALSE;
302
303 if (!wd->od->func_get_geometry(wd->widget, &nx, &ny, &nw, &nh)) return FALSE;
304
305 if (x) *x = nx;
306 if (y) *y = ny;
307 if (w) *w = nw;
308 if (h) *h = nh;
309
310 return TRUE;
311 }
312
ui_widget_set_coord(UIData * ui,WidgetData * wd,gint x,gint y,gint redraw)313 void ui_widget_set_coord(UIData *ui, WidgetData *wd, gint x, gint y, gint redraw)
314 {
315 gint ox, oy, ow, oh;
316 gint old_bounds;
317
318 if (!wd->od || !wd->od->func_set_coord) return;
319
320 if (!ui_widget_get_geometry(wd, &ox, &oy, &ow, &oh)) return;
321
322 wd->od->func_set_coord(wd->widget, x, y);
323
324 if (!ui) return;
325
326 old_bounds = wd->in_bounds;
327 skin_widget_check_bounds(ui->skin, wd);
328
329 if (!wd->in_bounds || !redraw) return;
330
331 /* change back */
332 pixbuf_copy_area(ui->skin->overlay, x, y,
333 ui->skin->pixbuf, x, y, ow, oh, FALSE);
334 ui_widget_sync_back(ui, wd);
335
336 /* redraw old location */
337 if (old_bounds) ui_display_redraw_area(ui, ox, oy, ow, oh, FALSE);
338
339 /* draw it */
340 ui_widget_draw(ui, wd, FALSE, TRUE);
341 }
342
ui_widget_set_size(UIData * ui,WidgetData * wd,gint dev_w,gint dev_h,gint redraw)343 void ui_widget_set_size(UIData *ui, WidgetData *wd, gint dev_w, gint dev_h, gint redraw)
344 {
345 gint ox, oy, ow, oh;
346 gint nx, ny, nw, nh;
347 gint old_bounds;
348
349 if (!wd->od || !wd->od->func_set_size) return;
350
351 if (!ui_widget_get_geometry(wd, &ox, &oy, &ow, &oh)) return;
352
353 wd->od->func_set_size(wd->widget, dev_w, dev_h);
354
355 if (!ui) return;
356
357 old_bounds = wd->in_bounds;
358 skin_widget_check_bounds(ui->skin, wd);
359
360 if (!wd->in_bounds || !redraw) return;
361
362 if (!ui_widget_get_geometry(wd, &nx, &ny, &nw, &nh)) return;
363
364 /* change back */
365 pixbuf_copy_area(ui->skin->overlay, nx, ny,
366 ui->skin->pixbuf, nx, ny, nw, nh, FALSE);
367 ui_widget_sync_back(ui, wd);
368
369 /* redraw old location */
370 if (old_bounds) ui_display_redraw_area(ui, ox, oy, ow, oh, FALSE);
371
372 /* draw it */
373 ui_widget_draw(ui, wd, FALSE, TRUE);
374 }
375
ui_widget_set_anchor(WidgetData * wd,gint right,gint bottom)376 void ui_widget_set_anchor(WidgetData *wd, gint right, gint bottom)
377 {
378 if (!wd) return;
379
380 wd->anchor_right = right;
381 wd->anchor_bottom = bottom;
382 }
383
ui_widget_find_by_coord(UIData * ui,gint x,gint y)384 WidgetData *ui_widget_find_by_coord(UIData *ui, gint x, gint y)
385 {
386 GList *work;
387
388 work = g_list_last(ui->skin->widget_list);
389 while(work)
390 {
391 WidgetData *wd = work->data;
392 gint wx, wy, ww, wh;
393
394 if (wd->od && wd->od->is_visible && ui_widget_get_geometry(wd, &wx, &wy, &ww, &wh) &&
395 x >= wx && x <= wx+ww && y >= wy && y <= wy+wh) return wd;
396
397 work = work->prev;
398 }
399
400 return NULL;
401 }
402
ui_widget_contacts_area(WidgetData * wd,gint x,gint y,gint w,gint h)403 gint ui_widget_contacts_area(WidgetData *wd, gint x, gint y, gint w, gint h)
404 {
405 gint wx, wy, ww, wh;
406
407 if (!ui_widget_get_geometry(wd, &wx, &wy, &ww, &wh) ||
408 x > wx + ww || x + w < wx || y > wy + wh || y + h < wy) return FALSE;
409
410 return TRUE;
411 }
412
413 /*
414 *-------------------------------
415 * widget data attachment
416 *-------------------------------
417 */
418
widget_data_list_find(GList * list,const gchar * key)419 GList *widget_data_list_find(GList *list, const gchar *key)
420 {
421 GList *work;
422
423 work = list;
424 while (work)
425 {
426 gchar *skey = work->data;
427
428 if (strcmp(skey, key) == 0) return work;
429 work = work->next;
430 if (work) work = work->next;
431 }
432
433 return NULL;
434 }
435
widget_data_list_set(GList * list,const gchar * key,const gchar * data)436 GList *widget_data_list_set(GList *list, const gchar *key, const gchar *data)
437 {
438 GList *work;
439
440 /* if key exists, change it (or if !data remove it) */
441 work = widget_data_list_find(list, key);
442 if (work)
443 {
444 if (!data)
445 {
446 gchar *k;
447 gchar *d;
448
449 k = work->data;
450 work = work->next;
451 d = work->data;
452
453 list = g_list_remove(list, k);
454 list = g_list_remove(list, d);
455
456 g_free(k);
457 g_free(d);
458 return list;
459 }
460 work = work->next;
461 g_free(work->data);
462 work->data = g_strdup(data);
463 return list;
464 }
465
466 if (!key || !data) return list;
467
468 list = g_list_append(list, g_strdup(key));
469 list = g_list_append(list, g_strdup(data));
470
471 return list;
472 }
473
ui_widget_set_data(WidgetData * wd,const gchar * key,const gchar * data)474 void ui_widget_set_data(WidgetData *wd, const gchar *key, const gchar *data)
475 {
476 if (!wd) return;
477
478 wd->data_list = widget_data_list_set(wd->data_list, key, data);
479 }
480
ui_widget_get_data(WidgetData * wd,const gchar * key)481 const gchar *ui_widget_get_data(WidgetData *wd, const gchar *key)
482 {
483 GList *work;
484
485 if (!wd || !key) return NULL;
486
487 work = widget_data_list_find(wd->data_list, key);
488 if (work && work->next)
489 {
490 work = work->next;
491 return work->data;
492 }
493
494 return NULL;
495 }
496
497 /* this a wrapper that get data with a key of "data", for use by the app
498 */
499
ui_widget_get_data_by_widget(UIData * ui,gpointer widget)500 const gchar *ui_widget_get_data_by_widget(UIData *ui, gpointer widget)
501 {
502 if (!ui) return NULL;
503
504 return ui_widget_get_data(skin_widget_get_by_widget(ui->skin, widget), "data");
505 }
506
507 /*
508 *-------------------------------
509 * widget function/type registry
510 *-------------------------------
511 */
512
513 static GList *widget_type_list = NULL;
514 static WidgetType widget_type_count = 0;
515
ui_widget_type_new(const gchar * description)516 WidgetObjectData *ui_widget_type_new(const gchar *description)
517 {
518 WidgetObjectData *od;
519
520 od = g_new0(WidgetObjectData, 1);
521
522 od->type = widget_type_count;
523 widget_type_count++;
524
525 od->priority = UI_WIDGET_PRIORITY_NORMAL;
526
527 od->description = g_strdup(description);
528 od->is_visible = TRUE;
529
530 widget_type_list = g_list_append(widget_type_list, od);
531
532 return od;
533 }
534
ui_widget_object_by_type(WidgetType type)535 WidgetObjectData *ui_widget_object_by_type(WidgetType type)
536 {
537 GList *work;
538
539 work = widget_type_list;
540 while(work)
541 {
542 WidgetObjectData *od = work->data;
543 if (od->type == type) return od;
544 work = work->next;
545 }
546
547 return NULL;
548 }
549
ui_widget_object_by_text(const gchar * description)550 WidgetObjectData *ui_widget_object_by_text(const gchar *description)
551 {
552 GList *work;
553
554 if (!description) return NULL;
555
556 work = widget_type_list;
557 while(work)
558 {
559 WidgetObjectData *od = work->data;
560 if (od->description && strcmp(od->description, description) == 0) return od;
561 work = work->next;
562 }
563
564 return NULL;
565 }
566
ui_widget_type_to_text(WidgetType type)567 const gchar *ui_widget_type_to_text(WidgetType type)
568 {
569 GList *work;
570
571 work = widget_type_list;
572 while(work)
573 {
574 WidgetObjectData *od = work->data;
575 if (od->type == type) return od->description;
576 work = work->next;
577 }
578
579 return "unknown";
580 }
581
ui_widget_object_copy(WidgetObjectData * src)582 WidgetObjectData *ui_widget_object_copy(WidgetObjectData *src)
583 {
584 WidgetObjectData *od;
585
586 if (!src) return NULL;
587
588 od = g_memdup(src, sizeof(WidgetObjectData));
589
590 od->description = g_strdup(src->description);
591
592 return od;
593 }
594
595