1 /*  DreamChess
2 **
3 **  DreamChess is the legal property of its developers, whose names are too
4 **  numerous to list here. Please refer to the AUTHORS.txt file distributed
5 **  with this source distribution.
6 **
7 **  This program is free software: you can redistribute it and/or modify
8 **  it under the terms of the GNU General Public License as published by
9 **  the Free Software Foundation, either version 3 of the License, or
10 **  (at your option) any later version.
11 **
12 **  This program is distributed in the hope that it will be useful,
13 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **  GNU General Public License for more details.
16 **
17 **  You should have received a copy of the GNU General Public License
18 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 /** @file
22  *  @brief Widget class implementation.
23  */
24 
25 #include <stdlib.h>
26 
27 #include <gamegui/dialog.h>
28 #include <gamegui/system.h>
29 #include <gamegui/widget.h>
30 
gg_widget_get_class_id(void)31 gg_class_id gg_widget_get_class_id(void) {
32 	GG_CHILD(GG_CLASS_ID_NONE)
33 }
34 
gg_widget_destroy(gg_widget_t * widget)35 void gg_widget_destroy(gg_widget_t *widget) {
36 	while (!TAILQ_EMPTY(&widget->callbacks)) {
37 		gg_widget_cb_list_t *cb = TAILQ_FIRST(&widget->callbacks);
38 		TAILQ_REMOVE(&widget->callbacks, cb, entries);
39 		free(cb);
40 	}
41 
42 	free(widget);
43 }
44 
gg_set_requested_size(gg_widget_t * widget,int width,int height)45 void gg_set_requested_size(gg_widget_t *widget, int width, int height) {
46 	widget->width_f = width;
47 	widget->height_f = height;
48 }
49 
gg_widget_get_requested_size(gg_widget_t * widget,int * width,int * height)50 void gg_widget_get_requested_size(gg_widget_t *widget, int *width, int *height) {
51 	if (width) {
52 		if (widget->width_f > widget->width)
53 			*width = widget->width_f;
54 		else
55 			*width = widget->width;
56 	}
57 
58 	if (height) {
59 		if (widget->height_f > widget->height)
60 			*height = widget->height_f;
61 		else
62 			*height = widget->height;
63 	}
64 }
65 
gg_set_size(gg_widget_t * widget,int width,int height)66 void gg_set_size(gg_widget_t *widget, int width, int height) {
67 	widget->width_a = width;
68 	widget->height_a = height;
69 }
70 
gg_get_focus_pos(gg_widget_t * widget)71 gg_rect_t gg_get_focus_pos(gg_widget_t *widget) {
72 	gg_rect_t rect;
73 
74 	rect.x = 0;
75 	rect.y = 0;
76 	rect.width = widget->width_a;
77 	rect.height = widget->height_a;
78 
79 	return rect;
80 }
81 
gg_set_focus_pos(gg_widget_t * widget,int x,int y)82 int gg_set_focus_pos(gg_widget_t *widget, int x, int y) {
83 	return 1;
84 }
85 
gg_widget_find_dialog(gg_widget_t * widget)86 gg_dialog_t *gg_widget_find_dialog(gg_widget_t *widget) {
87 	if (widget->parent == NULL)
88 		return NULL;
89 
90 	while (widget->parent != NULL)
91 		widget = widget->parent;
92 
93 	return GG_DIALOG(widget);
94 }
95 
gg_widget_init(gg_widget_t * widget)96 void gg_widget_init(gg_widget_t *widget) {
97 	widget->render = NULL;
98 	widget->input = NULL;
99 	widget->destroy = gg_widget_destroy;
100 	widget->get_requested_size = gg_widget_get_requested_size;
101 	widget->set_size = gg_set_size;
102 	widget->get_focus_pos = gg_get_focus_pos;
103 	widget->set_focus_pos = gg_set_focus_pos;
104 	widget->id = gg_widget_get_class_id();
105 	widget->enabled = 0;
106 	widget->width = widget->height = 0;
107 	widget->width_f = widget->height_f = -1;
108 	widget->width_a = widget->height_a = 0;
109 	widget->parent = NULL;
110 	TAILQ_INIT(&widget->callbacks);
111 }
112 
gg_widget_subscribe_signal(gg_widget_t * widget,gg_signal_t signal,gg_widget_cb_t callback,void * extra_data)113 void gg_widget_subscribe_signal(gg_widget_t *widget, gg_signal_t signal, gg_widget_cb_t callback, void *extra_data) {
114 	gg_widget_cb_list_t *cb = malloc(sizeof(gg_widget_cb_list_t));
115 	cb->signal = signal;
116 	cb->callback = callback;
117 	cb->extra_data = extra_data;
118 	TAILQ_INSERT_HEAD(&widget->callbacks, cb, entries);
119 }
120 
gg_widget_subscribe_signal_name(gg_widget_t * widget,gg_class_id id,char * name,gg_widget_cb_t callback,void * extra_data)121 int gg_widget_subscribe_signal_name(gg_widget_t *widget, gg_class_id id, char *name, gg_widget_cb_t callback,
122 									void *extra_data) {
123 	gg_signal_t signal = gg_signal_lookup(id, name);
124 
125 	if (signal == -1)
126 		return -1;
127 
128 	gg_widget_subscribe_signal(widget, signal, callback, extra_data);
129 	return 0;
130 }
131 
gg_widget_emit_signal(gg_widget_t * widget,gg_widget_t * emitter,gg_signal_t signal,void * data)132 void gg_widget_emit_signal(gg_widget_t *widget, gg_widget_t *emitter, gg_signal_t signal, void *data) {
133 	gg_widget_cb_list_t *cb_list;
134 
135 	TAILQ_FOREACH(cb_list, &widget->callbacks, entries) {
136 		if (cb_list->signal == signal) {
137 			if (cb_list->callback(widget, emitter, data, cb_list->extra_data))
138 				return;
139 		}
140 	}
141 
142 	if (widget->parent)
143 		gg_widget_emit_signal(widget->parent, emitter, signal, data);
144 }
145