ui/gtk/button.c

changeset 44
473954dc6b74
parent 32
e5f4d8af567e
child 45
ab71409644b0
--- 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

mercurial