1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "button.h"
33 #include "container.h"
34 #include <cx/allocator.h>
35 #include "../common/context.h"
36 #include "../common/object.h"
37
38 void ui_button_set_icon_name(GtkWidget *button,
const char *icon) {
39 if(!icon) {
40 return;
41 }
42
43 #ifdef UI_GTK4
44 gtk_button_set_icon_name(
GTK_BUTTON(button), icon);
45 #else
46 #if GTK_CHECK_VERSION(
2,
6,
0)
47 GtkWidget *image = gtk_image_new_from_icon_name(icon,
GTK_ICON_SIZE_BUTTON);
48 if(image) {
49 gtk_button_set_image(
GTK_BUTTON(button), image);
50 }
51 #else
52
53 #endif
54 #endif
55 }
56
57 GtkWidget* ui_create_button(
58 UiObject *obj,
59 const char *label,
60 const char *icon,
61 ui_callback onclick,
62 void *userdata,
63 int event_value,
64 bool activate_event)
65 {
66 GtkWidget *button = gtk_button_new_with_label(label);
67 ui_button_set_icon_name(button, icon);
68
69 if(onclick) {
70 UiEventData *event = malloc(
sizeof(UiEventData));
71 event->obj = obj;
72 event->userdata = userdata;
73 event->callback = onclick;
74 event->value = event_value;
75 event->customdata =
NULL;
76
77 g_signal_connect(
78 button,
79 "clicked",
80 G_CALLBACK(ui_button_clicked),
81 event);
82 g_signal_connect(
83 button,
84 "destroy",
85 G_CALLBACK(ui_destroy_userdata),
86 event);
87 if(activate_event) {
88 g_signal_connect(
89 button,
90 "activate",
91 G_CALLBACK(ui_button_clicked),
92 event);
93 }
94 }
95
96 return button;
97 }
98
99 UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) {
100 UiObject* current = uic_current_obj(obj);
101 GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata,
0,
FALSE);
102 ui_set_name_and_style(button, args.name, args.style_class);
103 ui_set_widget_groups(obj->ctx, button, args.groups);
104 UI_APPLY_LAYOUT1(current, args);
105 current->container->add(current->container, button,
FALSE);
106 return button;
107 }
108
109
110 void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
111 UiEvent e;
112 e.obj = event->obj;
113 e.window = event->obj->window;
114 e.document = event->obj->ctx->document;
115 e.eventdata =
NULL;
116 e.intval = event->value;
117 event->callback(&e, event->userdata);
118 }
119
120 int64_t ui_toggle_button_get(UiInteger *integer) {
121 GtkToggleButton *button = integer->obj;
122 integer->value = (
int)gtk_toggle_button_get_active(button);
123 return integer->value;
124 }
125
126 void ui_toggle_button_set(UiInteger *integer,
int64_t value) {
127 GtkToggleButton *button = integer->obj;
128 integer->value = value;
129 gtk_toggle_button_set_active(button, value !=
0 ?
TRUE :
FALSE);
130 }
131
132 void ui_toggled_obs(
void *widget, UiVarEventData *event) {
133 UiInteger *i = event->var->value;
134 UiEvent e;
135 e.obj = event->obj;
136 e.window = event->obj->window;
137 e.document = event->obj->ctx->document;
138 e.eventdata = event->var->value;
139 e.intval = i->get(i);
140
141 ui_notify_evt(i->observers, &e);
142 }
143
144 static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
145 UiEvent e;
146 e.obj = event->obj;
147 e.window = event->obj->window;
148 e.document = event->obj->ctx->document;
149 e.eventdata =
NULL;
150 e.intval = gtk_toggle_button_get_active(widget);
151 event->callback(&e, event->userdata);
152 }
153
154 static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) {
155 if(gtk_toggle_button_get_active(widget)) {
156 ui_set_group(event->obj->ctx, event->value);
157 }
else {
158 ui_unset_group(event->obj->ctx, event->value);
159 }
160 }
161
162 void ui_setup_togglebutton(
163 UiObject *obj,
164 GtkWidget *togglebutton,
165 const char *label,
166 const char *icon,
167 const char *varname,
168 UiInteger *value,
169 ui_callback onchange,
170 void *onchangedata,
171 int enable_state)
172 {
173 if(label) {
174 gtk_button_set_label(
GTK_BUTTON(togglebutton), label);
175 }
176 ui_button_set_icon_name(togglebutton, icon);
177
178 ui_bind_togglebutton(
179 obj,
180 togglebutton,
181 ui_toggle_button_get,
182 ui_toggle_button_set,
183 varname,
184 value,
185 (ui_toggled_func)ui_toggled_callback,
186 onchange,
187 onchangedata,
188 (ui_toggled_func)ui_togglebutton_enable_state_callback,
189 enable_state
190 );
191 }
192
193 void ui_bind_togglebutton(
194 UiObject *obj,
195 GtkWidget *widget,
196 int64_t (*getfunc)(UiInteger*),
197 void (*setfunc)(UiInteger*,
int64_t),
198 const char *varname,
199 UiInteger *value,
200 void (*toggled_callback)(
void*,
void*),
201 ui_callback onchange,
202 void *onchangedata,
203 void (*enable_state_func)(
void*,
void*),
204 int enable_state)
205 {
206 UiObject* current = uic_current_obj(obj);
207 UiVar* var = uic_widget_var(obj->ctx, current->ctx, value, varname,
UI_VAR_INTEGER);
208 if (var) {
209 UiInteger* value = (UiInteger*)var->value;
210 value->obj = widget;
211 value->get = getfunc;
212 value->set = setfunc;
213
214 UiVarEventData *event = malloc(
sizeof(UiVarEventData));
215 event->obj = obj;
216 event->var = var;
217 event->observers =
NULL;
218 event->callback =
NULL;
219 event->userdata =
NULL;
220
221 g_signal_connect(
222 widget,
223 "toggled",
224 G_CALLBACK(ui_toggled_obs),
225 event);
226 g_signal_connect(
227 widget,
228 "destroy",
229 G_CALLBACK(ui_destroy_vardata),
230 event);
231 }
232
233 if(onchange) {
234 UiEventData *event = malloc(
sizeof(UiEventData));
235 event->obj = obj;
236 event->userdata = onchangedata;
237 event->callback = onchange;
238 event->value =
0;
239 event->customdata =
NULL;
240
241 g_signal_connect(
242 widget,
243 "toggled",
244 G_CALLBACK(toggled_callback),
245 event);
246 g_signal_connect(
247 widget,
248 "destroy",
249 G_CALLBACK(ui_destroy_userdata),
250 event);
251 }
252
253 if(enable_state >
0) {
254 UiEventData *event = malloc(
sizeof(UiEventData));
255 event->obj = obj;
256 event->userdata =
NULL;
257 event->callback =
NULL;
258 event->value = enable_state;
259 event->customdata =
NULL;
260
261 g_signal_connect(
262 widget,
263 "toggled",
264 G_CALLBACK(enable_state_func),
265 event);
266 g_signal_connect(
267 widget,
268 "destroy",
269 G_CALLBACK(ui_destroy_userdata),
270 event);
271 }
272 }
273
274 static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) {
275 UiObject* current = uic_current_obj(obj);
276
277 ui_setup_togglebutton(
278 current,
279 widget,
280 args.label,
281 args.icon,
282 args.varname,
283 args.value,
284 args.onchange,
285 args.onchangedata,
286 args.enable_group);
287 ui_set_name_and_style(widget, args.name, args.style_class);
288 ui_set_widget_groups(obj->ctx, widget, args.groups);
289
290 UI_APPLY_LAYOUT1(current, args);
291 current->container->add(current->container, widget,
FALSE);
292
293 return widget;
294 }
295
296 UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
297 return togglebutton_create(obj, gtk_toggle_button_new(), args);
298 }
299
300 #if GTK_MAJOR_VERSION >=
4
301
302 int64_t ui_check_button_get(UiInteger *integer) {
303 GtkCheckButton *button = integer->obj;
304 integer->value = (
int)gtk_check_button_get_active(button);
305 return integer->value;
306 }
307
308 void ui_check_button_set(UiInteger *integer,
int64_t value) {
309 GtkCheckButton *button = integer->obj;
310 integer->value = value;
311 gtk_check_button_set_active(button, value !=
0 ?
TRUE :
FALSE);
312 }
313
314 static void ui_checkbox_callback(GtkCheckButton *widget, UiEventData *event) {
315 UiEvent e;
316 e.obj = event->obj;
317 e.window = event->obj->window;
318 e.document = event->obj->ctx->document;
319 e.eventdata =
NULL;
320 e.intval = gtk_check_button_get_active(widget);
321 event->callback(&e, event->userdata);
322 }
323
324 static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event) {
325 if(gtk_check_button_get_active(widget)) {
326 ui_set_group(event->obj->ctx, event->value);
327 }
else {
328 ui_unset_group(event->obj->ctx, event->value);
329 }
330 }
331
332 UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
333 UiObject* current = uic_current_obj(obj);
334
335 GtkWidget *widget = gtk_check_button_new_with_label(args.label);
336 ui_bind_togglebutton(
337 obj,
338 widget,
339 ui_check_button_get,
340 ui_check_button_set,
341 args.varname,
342 args.value,
343 (ui_toggled_func)ui_checkbox_callback,
344 args.onchange,
345 args.onchangedata,
346 (ui_toggled_func)ui_checkbox_enable_state,
347 args.enable_group);
348
349 ui_set_name_and_style(widget, args.name, args.style_class);
350 ui_set_widget_groups(obj->ctx, widget, args.groups);
351
352 UI_APPLY_LAYOUT1(current, args);
353 current->container->add(current->container, widget,
FALSE);
354
355 return widget;
356 }
357
358 #else
359 UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
360 return togglebutton_create(obj, gtk_check_button_new(), args);
361 }
362 #endif
363
364 UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
365 #ifdef UI_GTK3
366 return NULL;
367 #else
368 return ui_checkbox_create(obj, args);
369 #endif
370 }
371
372 #if GTK_MAJOR_VERSION >=
4
373 #define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label)
374 #define RADIOBUTTON_SET_GROUP(button, group)
375 #define RADIOBUTTON_GET_GROUP(button)
GTK_CHECK_BUTTON(button)
376 #define RADIOBUTTON_GET_ACTIVE(button) gtk_check_button_get_active(
GTK_CHECK_BUTTON(button))
377 #else
378 #define RADIOBUTTON_NEW(group, label) gtk_radio_button_new_with_label(group, label)
379 #define RADIOBUTTON_SET_GROUP(button, group)
380 #define RADIOBUTTON_GET_GROUP(button) gtk_radio_button_get_group(
GTK_RADIO_BUTTON(button))
381 #define RADIOBUTTON_GET_ACTIVE(button) gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(button))
382 #endif
383
384 static void radiobutton_toggled(
void *widget, UiEventData *event) {
385 UiEvent e;
386 e.obj = event->obj;
387 e.window = event->obj->window;
388 e.document = event->obj->ctx->document;
389 e.eventdata =
NULL;
390 e.intval =
RADIOBUTTON_GET_ACTIVE(widget);
391 event->callback(&e, event->userdata);
392 }
393
394 typedef struct UiRadioButtonData {
395 UiInteger *value;
396 UiVarEventData *eventdata;
397 UiBool first;
398 } UiRadioButtonData;
399
400 static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) {
401 if(data->first) {
402 ui_destroy_vardata(w, data->eventdata);
403 g_slist_free(data->value->obj);
404 data->value->obj =
NULL;
405 data->value->get =
NULL;
406 data->value->set =
NULL;
407 }
else {
408 free(data->eventdata);
409 }
410 free(data);
411 }
412
413 UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
414 UiObject* current = uic_current_obj(obj);
415
416 GSList *rg =
NULL;
417 UiInteger *rgroup;
418
419 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_INTEGER);
420
421 UiBool first =
FALSE;
422 if(var) {
423 rgroup = var->value;
424 rg = rgroup->obj;
425 if(!rg) {
426 first =
TRUE;
427 }
428 }
429
430 GtkWidget *rbutton =
RADIOBUTTON_NEW(rg, args.label);
431 ui_set_name_and_style(rbutton, args.name, args.style_class);
432 ui_set_widget_groups(obj->ctx, rbutton, args.groups);
433 if(rgroup) {
434 #if GTK_MAJOR_VERSION >=
4
435 if(rg) {
436 gtk_check_button_set_group(
GTK_CHECK_BUTTON(rbutton), rg->data);
437 }
438 rg = g_slist_prepend(rg, rbutton);
439 #else
440 gtk_radio_button_set_group(
GTK_RADIO_BUTTON(rbutton), rg);
441 rg = gtk_radio_button_get_group(
GTK_RADIO_BUTTON(rbutton));
442 #endif
443
444 rgroup->obj = rg;
445 rgroup->get = ui_radiobutton_get;
446 rgroup->set = ui_radiobutton_set;
447
448 ui_radiobutton_set(rgroup, rgroup->value);
449
450 UiVarEventData *event = malloc(
sizeof(UiVarEventData));
451 event->obj = obj;
452 event->var = var;
453 event->observers =
NULL;
454 event->callback =
NULL;
455 event->userdata =
NULL;
456
457 UiRadioButtonData *rbdata = malloc(
sizeof(UiRadioButtonData));
458 rbdata->value = rgroup;
459 rbdata->eventdata = event;
460 rbdata->first = first;
461
462 g_signal_connect(
463 rbutton,
464 "toggled",
465 G_CALLBACK(ui_radio_obs),
466 event);
467 g_signal_connect(
468 rbutton,
469 "destroy",
470 G_CALLBACK(destroy_radiobutton),
471 rbdata);
472 }
473
474 if(args.onchange) {
475 UiEventData *event = malloc(
sizeof(UiEventData));
476 event->obj = obj;
477 event->userdata = args.onchangedata;
478 event->callback = args.onchange;
479 event->value =
0;
480 event->customdata =
NULL;
481
482 g_signal_connect(
483 rbutton,
484 "toggled",
485 G_CALLBACK(radiobutton_toggled),
486 event);
487 g_signal_connect(
488 rbutton,
489 "destroy",
490 G_CALLBACK(ui_destroy_userdata),
491 event);
492 }
493
494 UI_APPLY_LAYOUT1(current, args);
495 current->container->add(current->container, rbutton,
FALSE);
496
497 return rbutton;
498 }
499
500 void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) {
501 UiInteger *i = event->var->value;
502
503 UiEvent e;
504 e.obj = event->obj;
505 e.window = event->obj->window;
506 e.document = event->obj->ctx->document;
507 e.eventdata =
NULL;
508 e.intval = i->get(i);
509
510 ui_notify_evt(i->observers, &e);
511 }
512
513 #if GTK_MAJOR_VERSION >=
4
514 int64_t ui_radiobutton_get(UiInteger *value) {
515 int selection =
0;
516 GSList *ls = value->obj;
517 int i =
0;
518 guint len = g_slist_length(ls);
519 while(ls) {
520 if(gtk_check_button_get_active(
GTK_CHECK_BUTTON(ls->data))) {
521 selection = len - i -
1;
522 break;
523 }
524 ls = ls->next;
525 i++;
526 }
527
528 value->value = selection;
529 return selection;
530 }
531
532 void ui_radiobutton_set(UiInteger *value,
int64_t i) {
533 GSList *ls = value->obj;
534 int s = g_slist_length(ls) -
1 - i;
535 int j =
0;
536 while(ls) {
537 if(j == s) {
538 gtk_check_button_set_active(
GTK_CHECK_BUTTON(ls->data),
TRUE);
539 break;
540 }
541 ls = ls->next;
542 j++;
543 }
544
545 value->value = i;
546 }
547 #else
548 int64_t ui_radiobutton_get(UiInteger *value) {
549 int selection =
0;
550 GSList *ls = value->obj;
551 int i =
0;
552 guint len = g_slist_length(ls);
553 while(ls) {
554 if(gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(ls->data))) {
555 selection = len - i -
1;
556 break;
557 }
558 ls = ls->next;
559 i++;
560 }
561
562 value->value = selection;
563 return selection;
564 }
565
566 void ui_radiobutton_set(UiInteger *value,
int64_t i) {
567 GSList *ls = value->obj;
568 int s = g_slist_length(ls) -
1 - i;
569 int j =
0;
570 while(ls) {
571 if(j == s) {
572 gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(ls->data),
TRUE);
573 break;
574 }
575 ls = ls->next;
576 j++;
577 }
578
579 value->value = i;
580 }
581 #endif
582