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