diff -r ef01d2c90128 -r 473954dc6b74 ui/gtk/button.c --- a/ui/gtk/button.c Mon Jun 17 21:20:58 2024 +0200 +++ b/ui/gtk/button.c Sun Sep 29 13:32:51 2024 +0200 @@ -54,20 +54,21 @@ #endif } -UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) { - UiObject* current = uic_current_obj(obj); - GtkWidget *button = gtk_button_new(); - if(args.label) { - gtk_button_set_label(GTK_BUTTON(button), args.label); - } - ui_button_set_icon_name(button, args.icon); - +GtkWidget* ui_create_button( + UiObject *obj, + const char *label, + const char *icon, + ui_callback onclick, + void *userdata) +{ + GtkWidget *button = gtk_button_new_with_label(label); + ui_button_set_icon_name(button, icon); - if(args.onclick) { + if(onclick) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; - event->userdata = args.onclickdata; - event->callback = args.onclick; + event->userdata = userdata; + event->callback = onclick; event->value = 0; event->customdata = NULL; @@ -83,9 +84,14 @@ event); } + return button; +} + +UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) { + UiObject* current = uic_current_obj(obj); + GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata); UI_APPLY_LAYOUT1(current, args); current->container->add(current->container, button, FALSE); - return button; } @@ -112,32 +118,73 @@ gtk_toggle_button_set_active(button, value != 0 ? TRUE : FALSE); } -void ui_toggled_obs(GtkToggleToolButton *widget, UiVarEventData *event) { +void ui_toggled_obs(void *widget, UiVarEventData *event) { + UiInteger *i = event->var->value; UiEvent e; e.obj = event->obj; e.window = event->obj->window; e.document = event->obj->ctx->document; e.eventdata = event->var->value; - e.intval = gtk_toggle_tool_button_get_active(widget); + e.intval = i->get(i); - UiInteger *i = event->var->value; ui_notify_evt(i->observers, &e); } -static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) { - UiObject* current = uic_current_obj(obj); +static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) { + UiEvent e; + e.obj = event->obj; + e.window = event->obj->window; + e.document = event->obj->ctx->document; + e.eventdata = NULL; + e.intval = gtk_toggle_button_get_active(widget); + event->callback(&e, event->userdata); +} + +void ui_setup_togglebutton( + UiObject *obj, + GtkWidget *togglebutton, + const char *label, + const char *icon, + const char *varname, + UiInteger *value, + ui_callback onchange, + void *onchangedata) +{ + if(label) { + gtk_button_set_label(GTK_BUTTON(togglebutton), label); + } + ui_button_set_icon_name(togglebutton, icon); - if(args.label) { - gtk_button_set_label(GTK_BUTTON(widget), args.label); - } - ui_button_set_icon_name(widget, args.icon); - - UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); + ui_bind_togglebutton( + obj, + togglebutton, + ui_toggle_button_get, + ui_toggle_button_set, + varname, + value, + (ui_toggled_func)ui_toggled_callback, + onchange, + onchangedata); +} + +void ui_bind_togglebutton( + UiObject *obj, + GtkWidget *widget, + int64_t (*getfunc)(UiInteger*), + void (*setfunc)(UiInteger*, int64_t), + const char *varname, + UiInteger *value, + void (*toggled_callback)(void*, void*), + ui_callback onchange, + void *onchangedata) +{ + UiObject* current = uic_current_obj(obj); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, value, varname, UI_VAR_INTEGER); if (var) { UiInteger* value = (UiInteger*)var->value; value->obj = widget; - value->get = ui_toggle_button_get; - value->set = ui_toggle_button_set; + value->get = getfunc; + value->set = setfunc; UiVarEventData *event = malloc(sizeof(UiVarEventData)); event->obj = obj; @@ -148,7 +195,7 @@ g_signal_connect( widget, - "clicked", + "toggled", G_CALLBACK(ui_toggled_obs), event); g_signal_connect( @@ -158,6 +205,32 @@ event); } + if(onchange) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = onchangedata; + event->callback = onchange; + event->value = 0; + event->customdata = NULL; + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(toggled_callback), + event); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + } +} + +static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) { + UiObject* current = uic_current_obj(obj); + + ui_setup_togglebutton(current, widget, args.label, args.icon, args.varname, args.value, args.onchange, args.onchangedata); + UI_APPLY_LAYOUT1(current, args); current->container->add(current->container, widget, FALSE); @@ -168,9 +241,56 @@ return togglebutton_create(obj, gtk_toggle_button_new(), args); } +#if GTK_MAJOR_VERSION >= 4 + +int64_t ui_check_button_get(UiInteger *integer) { + GtkCheckButton *button = integer->obj; + integer->value = (int)gtk_check_button_get_active(button); + return integer->value; +} + +void ui_check_button_set(UiInteger *integer, int64_t value) { + GtkCheckButton *button = integer->obj; + integer->value = value; + gtk_check_button_set_active(button, value != 0 ? TRUE : FALSE); +} + +static void ui_checkbox_callback(GtkCheckButton *widget, UiEventData *event) { + UiEvent e; + e.obj = event->obj; + e.window = event->obj->window; + e.document = event->obj->ctx->document; + e.eventdata = NULL; + e.intval = gtk_check_button_get_active(widget); + event->callback(&e, event->userdata); +} + +UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { + UiObject* current = uic_current_obj(obj); + + GtkWidget *widget = gtk_check_button_new_with_label(args.label); + ui_bind_togglebutton( + obj, + widget, + ui_check_button_get, + ui_check_button_set, + args.varname, + args.value, + (ui_toggled_func)ui_checkbox_callback, + args.onchange, + args.onchangedata); + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, widget, FALSE); + + return widget; +} + +#else UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { return togglebutton_create(obj, gtk_check_button_new(), args); } +#endif UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) { #ifdef UI_GTK3 @@ -180,10 +300,27 @@ #endif } - +#if GTK_MAJOR_VERSION >= 4 +#define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label) +#define RADIOBUTTON_SET_GROUP(button, group) +#define RADIOBUTTON_GET_GROUP(button) GTK_CHECK_BUTTON(button) +#define RADIOBUTTON_GET_ACTIVE(button) gtk_check_button_get_active(GTK_CHECK_BUTTON(button)) +#else +#define RADIOBUTTON_NEW(group, label) gtk_radio_button_new_with_label(group, label) +#define RADIOBUTTON_SET_GROUP(button, group) /* noop */ +#define RADIOBUTTON_GET_GROUP(button) gtk_radio_button_get_group(GTK_RADIO_BUTTON(button)) +#define RADIOBUTTON_GET_ACTIVE(button) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) +#endif - - +static void radiobutton_toggled(void *widget, UiEventData *event) { + UiEvent e; + e.obj = event->obj; + e.window = event->obj->window; + e.document = event->obj->ctx->document; + e.eventdata = NULL; + e.intval = RADIOBUTTON_GET_ACTIVE(widget); + event->callback(&e, event->userdata); +} UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) { UiObject* current = uic_current_obj(obj); @@ -191,12 +328,7 @@ GSList *rg = NULL; UiInteger *rgroup; - UiVar* var = NULL; - if (args.value) { - var = uic_create_value_var(current->ctx, args.value); - } else if (args.varname) { - var = uic_create_var(obj->ctx, args.varname, UI_VAR_INTEGER); - } + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); UiBool first = FALSE; if(var) { @@ -207,10 +339,18 @@ } } - GtkWidget *rbutton = gtk_radio_button_new_with_label(rg, args.label ? args.label : ""); - rg = gtk_radio_button_get_group(GTK_RADIO_BUTTON(rbutton)); - + GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args.label); if(rgroup) { +#if GTK_MAJOR_VERSION >= 4 + if(rg) { + gtk_check_button_set_group(GTK_CHECK_BUTTON(rbutton), rg->data); + } + rg = g_slist_prepend(rg, rbutton); +#else + gtk_radio_button_set_group(GTK_RADIO_BUTTON(rbutton), rg); + rg = gtk_radio_button_get_group(GTK_RADIO_BUTTON(rbutton)); +#endif + rgroup->obj = rg; rgroup->get = ui_radiobutton_get; rgroup->set = ui_radiobutton_set; @@ -226,7 +366,7 @@ g_signal_connect( rbutton, - "clicked", + "toggled", G_CALLBACK(ui_radio_obs), event); if(first) { @@ -238,13 +378,33 @@ } } + if(args.onchange) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = args.onchangedata; + event->callback = args.onchange; + event->value = 0; + event->customdata = NULL; + + g_signal_connect( + rbutton, + "toggled", + G_CALLBACK(radiobutton_toggled), + event); + g_signal_connect( + rbutton, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + } + UiContainer *ct = uic_get_current_container(obj); ct->add(ct, rbutton, FALSE); return rbutton; } -void ui_radio_obs(GtkToggleToolButton *widget, UiVarEventData *event) { +void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) { UiInteger *i = event->var->value; UiEvent e; @@ -257,6 +417,41 @@ ui_notify_evt(i->observers, &e); } +#if GTK_MAJOR_VERSION >= 4 +int64_t ui_radiobutton_get(UiInteger *value) { + int selection = 0; + GSList *ls = value->obj; + int i = 0; + guint len = g_slist_length(ls); + while(ls) { + if(gtk_check_button_get_active(GTK_CHECK_BUTTON(ls->data))) { + selection = len - i - 1; + break; + } + ls = ls->next; + i++; + } + + value->value = selection; + return selection; +} + +void ui_radiobutton_set(UiInteger *value, int64_t i) { + GSList *ls = value->obj; + int s = g_slist_length(ls) - 1 - i; + int j = 0; + while(ls) { + if(j == s) { + gtk_check_button_set_active(GTK_CHECK_BUTTON(ls->data), TRUE); + break; + } + ls = ls->next; + j++; + } + + value->value = i; +} +#else int64_t ui_radiobutton_get(UiInteger *value) { int selection = 0; GSList *ls = value->obj; @@ -290,4 +485,4 @@ value->value = i; } - +#endif