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; |