ui/gtk/button.c

changeset 431
bb7da585debc
parent 403
b59935b2de79
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 31
32 #include "button.h" 32 #include "button.h"
33 #include "container.h" 33 #include "container.h"
34 #include <ucx/mempool.h> 34 #include <cx/allocator.h>
35 #include "../common/context.h" 35 #include "../common/context.h"
36 #include "../common/object.h" 36 #include "../common/object.h"
37 37
38 UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { 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 // TODO
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 {
39 GtkWidget *button = gtk_button_new_with_label(label); 66 GtkWidget *button = gtk_button_new_with_label(label);
40 67 ui_button_set_icon_name(button, icon);
41 if(f) { 68
69 if(onclick) {
42 UiEventData *event = malloc(sizeof(UiEventData)); 70 UiEventData *event = malloc(sizeof(UiEventData));
43 event->obj = obj; 71 event->obj = obj;
44 event->userdata = data; 72 event->userdata = userdata;
45 event->callback = f; 73 event->callback = onclick;
46 event->value = 0; 74 event->value = event_value;
75 event->customdata = NULL;
47 76
48 g_signal_connect( 77 g_signal_connect(
49 button, 78 button,
50 "clicked", 79 "clicked",
51 G_CALLBACK(ui_button_clicked), 80 G_CALLBACK(ui_button_clicked),
53 g_signal_connect( 82 g_signal_connect(
54 button, 83 button,
55 "destroy", 84 "destroy",
56 G_CALLBACK(ui_destroy_userdata), 85 G_CALLBACK(ui_destroy_userdata),
57 event); 86 event);
58 } 87 if(activate_event) {
59 88 g_signal_connect(
60 UiContainer *ct = uic_get_current_container(obj); 89 button,
61 ct->add(ct, button, FALSE); 90 "activate",
62 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);
63 return button; 106 return button;
64 } 107 }
65 108
66 109
67 void ui_button_clicked(GtkWidget *widget, UiEventData *event) { 110 void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
84 GtkToggleButton *button = integer->obj; 127 GtkToggleButton *button = integer->obj;
85 integer->value = value; 128 integer->value = value;
86 gtk_toggle_button_set_active(button, value != 0 ? TRUE : FALSE); 129 gtk_toggle_button_set_active(button, value != 0 ? TRUE : FALSE);
87 } 130 }
88 131
89 void ui_toggled_obs(GtkToggleToolButton *widget, UiVarEventData *event) { 132 void ui_toggled_obs(void *widget, UiVarEventData *event) {
133 UiInteger *i = event->var->value;
90 UiEvent e; 134 UiEvent e;
91 e.obj = event->obj; 135 e.obj = event->obj;
92 e.window = event->obj->window; 136 e.window = event->obj->window;
93 e.document = event->obj->ctx->document; 137 e.document = event->obj->ctx->document;
94 e.eventdata = event->var->value; 138 e.eventdata = event->var->value;
95 e.intval = gtk_toggle_tool_button_get_active(widget); 139 e.intval = i->get(i);
96 140
97 UiInteger *i = event->var->value;
98 ui_notify_evt(i->observers, &e); 141 ui_notify_evt(i->observers, &e);
99 } 142 }
100 143
101 UIWIDGET ui_checkbox_var(UiObject *obj, char *label, UiVar *var) { 144 static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
102 GtkWidget *button = gtk_check_button_new_with_label(label); 145 UiEvent e;
103 146 e.obj = event->obj;
104 // bind value 147 e.window = event->obj->window;
105 if(var) { 148 e.document = event->obj->ctx->document;
106 UiInteger *value = var->value; 149 e.eventdata = NULL;
107 value->obj = GTK_TOGGLE_BUTTON(button); 150 e.intval = gtk_toggle_button_get_active(widget);
108 value->get = ui_toggle_button_get; 151 event->callback(&e, event->userdata);
109 value->set = ui_toggle_button_set; 152 }
110 gtk_toggle_button_set_active(value->obj, value->value); 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;
111 213
112 UiVarEventData *event = malloc(sizeof(UiVarEventData)); 214 UiVarEventData *event = malloc(sizeof(UiVarEventData));
113 event->obj = obj; 215 event->obj = obj;
114 event->var = var; 216 event->var = var;
115 event->observers = NULL; 217 event->observers = NULL;
116 218 event->callback = NULL;
117 g_signal_connect( 219 event->userdata = NULL;
118 button, 220
119 "clicked", 221 g_signal_connect(
222 widget,
223 "toggled",
120 G_CALLBACK(ui_toggled_obs), 224 G_CALLBACK(ui_toggled_obs),
121 event); 225 event);
122 g_signal_connect( 226 g_signal_connect(
123 button, 227 widget,
124 "destroy", 228 "destroy",
125 G_CALLBACK(ui_destroy_vardata), 229 G_CALLBACK(ui_destroy_vardata),
126 event); 230 event);
127 } 231 }
128 232
129 UiContainer *ct = uic_get_current_container(obj); 233 if(onchange) {
130 ct->add(ct, button, FALSE); 234 UiEventData *event = malloc(sizeof(UiEventData));
131 235 event->obj = obj;
132 return button; 236 event->userdata = onchangedata;
133 } 237 event->callback = onchange;
134 238 event->value = 0;
135 UIWIDGET ui_checkbox(UiObject *obj, char *label, UiInteger *value) { 239 event->customdata = NULL;
136 UiVar *var = NULL; 240
137 if(value) { 241 g_signal_connect(
138 var = malloc(sizeof(UiVar)); 242 widget,
139 var->value = value; 243 "toggled",
140 var->type = UI_VAR_SPECIAL; 244 G_CALLBACK(toggled_callback),
141 } 245 event);
142 return ui_checkbox_var(obj, label, var); 246 g_signal_connect(
143 } 247 widget,
144 248 "destroy",
145 UIWIDGET ui_checkbox_nv(UiObject *obj, char *label, char *varname) { 249 G_CALLBACK(ui_destroy_userdata),
146 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_INTEGER); 250 event);
147 return ui_checkbox_var(obj, label, var); 251 }
148 } 252
149 253 if(enable_state > 0) {
150 254 UiEventData *event = malloc(sizeof(UiEventData));
151 UIWIDGET ui_radiobutton_var(UiObject *obj, char *label, UiVar *var) { 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; // TODO
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) /* noop */
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
152 GSList *rg = NULL; 416 GSList *rg = NULL;
153 UiInteger *rgroup; 417 UiInteger *rgroup;
154 418
419 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
420
421 UiBool first = FALSE;
155 if(var) { 422 if(var) {
156 rgroup = var->value; 423 rgroup = var->value;
157 rg = rgroup->obj; 424 rg = rgroup->obj;
158 } 425 if(!rg) {
159 426 first = TRUE;
160 GtkWidget *rbutton = gtk_radio_button_new_with_label(rg, label); 427 }
161 rg = gtk_radio_button_get_group(GTK_RADIO_BUTTON(rbutton)); 428 }
162 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);
163 if(rgroup) { 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
164 rgroup->obj = rg; 444 rgroup->obj = rg;
165 rgroup->get = ui_radiobutton_get; 445 rgroup->get = ui_radiobutton_get;
166 rgroup->set = ui_radiobutton_set; 446 rgroup->set = ui_radiobutton_set;
167 447
168 ui_radiobutton_set(rgroup, rgroup->value); 448 ui_radiobutton_set(rgroup, rgroup->value);
169 449
170 UiVarEventData *event = malloc(sizeof(UiVarEventData)); 450 UiVarEventData *event = malloc(sizeof(UiVarEventData));
171 event->obj = obj; 451 event->obj = obj;
172 event->var = var; 452 event->var = var;
173 event->observers = NULL; 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;
174 461
175 g_signal_connect( 462 g_signal_connect(
176 rbutton, 463 rbutton,
177 "clicked", 464 "toggled",
178 G_CALLBACK(ui_radio_obs), 465 G_CALLBACK(ui_radio_obs),
179 event); 466 event);
180 g_signal_connect( 467 g_signal_connect(
181 rbutton, 468 rbutton,
182 "destroy", 469 "destroy",
183 G_CALLBACK(ui_destroy_vardata), 470 G_CALLBACK(destroy_radiobutton),
184 event); 471 rbdata);
185 } 472 }
186 473
187 UiContainer *ct = uic_get_current_container(obj); 474 if(args.onchange) {
188 ct->add(ct, rbutton, FALSE); 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);
189 496
190 return rbutton; 497 return rbutton;
191 } 498 }
192 499
193 UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { 500 void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) {
194 UiVar *var = NULL;
195 if(rgroup) {
196 var = malloc(sizeof(UiVar));
197 var->value = rgroup;
198 var->type = UI_VAR_SPECIAL;
199 }
200 return ui_radiobutton_var(obj, label, var);
201 }
202
203 UIWIDGET ui_radiobutton_nv(UiObject *obj, char *label, char *varname) {
204 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_INTEGER);
205 return ui_radiobutton_var(obj, label, var);
206 }
207
208 void ui_radio_obs(GtkToggleToolButton *widget, UiVarEventData *event) {
209 UiInteger *i = event->var->value; 501 UiInteger *i = event->var->value;
210 502
211 UiEvent e; 503 UiEvent e;
212 e.obj = event->obj; 504 e.obj = event->obj;
213 e.window = event->obj->window; 505 e.window = event->obj->window;
216 e.intval = i->get(i); 508 e.intval = i->get(i);
217 509
218 ui_notify_evt(i->observers, &e); 510 ui_notify_evt(i->observers, &e);
219 } 511 }
220 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
221 int64_t ui_radiobutton_get(UiInteger *value) { 548 int64_t ui_radiobutton_get(UiInteger *value) {
222 int selection = 0; 549 int selection = 0;
223 GSList *ls = value->obj; 550 GSList *ls = value->obj;
224 int i = 0; 551 int i = 0;
225 guint len = g_slist_length(ls); 552 guint len = g_slist_length(ls);
249 j++; 576 j++;
250 } 577 }
251 578
252 value->value = i; 579 value->value = i;
253 } 580 }
254 581 #endif

mercurial