ui/gtk/button.c

changeset 109
c3dfcb8f0be7
parent 108
77254bd6dccb
child 110
c00e968d018b
--- a/ui/gtk/button.c	Sun Jul 20 22:04:39 2025 +0200
+++ b/ui/gtk/button.c	Sun Aug 24 15:24:16 2025 +0200
@@ -32,6 +32,8 @@
 #include "button.h"
 #include "container.h"
 #include <cx/allocator.h>
+#include <cx/buffer.h>
+#include <cx/json.h>
 #include "../common/context.h"
 #include "../common/object.h"
 
@@ -120,6 +122,14 @@
     event->callback(&e, event->userdata);
 }
 
+void ui_button_set_label(UIWIDGET button, const char *label) {
+    gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_button_set_icon(UIWIDGET button, const char *icon) {
+    ui_button_set_icon_name(button, icon);
+}
+
 int64_t ui_toggle_button_get(UiInteger *integer) {
     GtkToggleButton *button = integer->obj;
     integer->value = (int)gtk_toggle_button_get_active(button);
@@ -594,3 +604,280 @@
     value->value = i;
 }
 #endif
+
+
+static void ui_destroy_linkbutton(GtkWidget *widget, UiLinkButton *data) {
+    free(data->link);
+    free(data);
+}
+
+static const char* linkbutton_get_uri(UiLinkButton *link) {
+    if(link->type == UI_LINK_BUTTON) {
+        return link->link;
+    } else {
+        return gtk_link_button_get_uri(GTK_LINK_BUTTON(link->widget));
+    }
+}
+
+static void linkbutton_set_uri(UiLinkButton *link, const char *uri) {
+    if(link->type == UI_LINK_BUTTON) {
+        free(link->link);
+        link->link = uri ? strdup(uri) : NULL;
+    } else {
+        gtk_link_button_set_uri(GTK_LINK_BUTTON(link->widget), uri);
+    }
+}
+
+static gboolean linkbutton_get_visited(UiLinkButton *link) {
+    if(link->type == UI_LINK_BUTTON) {
+        return FALSE;
+    } else {
+        gtk_link_button_get_visited(GTK_LINK_BUTTON(link->widget));
+    }
+}
+
+static void linkbutton_set_visited(UiLinkButton *link, gboolean visited) {
+    if(link->type != UI_LINK_BUTTON) {
+        gtk_link_button_set_visited(GTK_LINK_BUTTON(link->widget), visited);
+    }
+}
+
+/*
+ * Apply linkbutton settings from json. Expects jsonvalue to be a valid
+ * json object.
+ * 
+ * {
+ *     "label": "label text",
+ *     "uri": "http://example.com",
+ *     "visited": true
+ * }
+ * 
+ */
+static void linkbutton_apply_value(UiLinkButton *link, const char *jsonvalue) {
+    CxJson json;
+    cxJsonInit(&json, NULL);
+    cxJsonFill(&json, jsonvalue);
+    
+    CxJsonValue *value;
+    if(cxJsonNext(&json, &value) == CX_JSON_NO_ERROR) {
+        if(cxJsonIsObject(value)) {
+            CxJsonValue *label = cxJsonObjGet(value, "label");
+            CxJsonValue *uri = cxJsonObjGet(value, "uri");
+            CxJsonValue *visited = cxJsonObjGet(value, "visited");
+            if(label) {
+                gtk_button_set_label(GTK_BUTTON(link->widget), cxJsonIsString(label) ? cxJsonAsString(label) : NULL);
+            }
+            if(uri) {
+                linkbutton_set_uri(link, cxJsonIsString(uri) ? cxJsonAsString(uri) : NULL);
+                
+            }
+            if(visited) {
+                linkbutton_set_visited(link, cxJsonIsBool(visited) ? cxJsonAsBool(visited) : FALSE);
+            }
+        }        
+        cxJsonValueFree(value);
+    }
+    cxJsonDestroy(&json);
+}
+
+static char* create_linkbutton_jsonvalue(const char *label, const char *uri, gboolean include_null, gboolean visited, gboolean set_visited) {
+    CxJsonValue *obj = cxJsonCreateObj(NULL);
+    if(label) {
+        cxJsonObjPutString(obj, CX_STR("label"), label);
+    } else if(include_null) {
+        cxJsonObjPutLiteral(obj, CX_STR("label"), CX_JSON_NULL);
+    }
+    
+    if(uri) {
+        cxJsonObjPutString(obj, CX_STR("uri"), uri);
+    } else if(include_null) {
+        cxJsonObjPutLiteral(obj, CX_STR("uri"), CX_JSON_NULL);
+    }
+    
+    if(set_visited) {
+        cxJsonObjPutLiteral(obj, CX_STR("visited"), visited ? CX_JSON_TRUE : CX_JSON_FALSE);
+    }
+    
+    CxJsonWriter writer = cxJsonWriterCompact();
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, 128, NULL, CX_BUFFER_AUTO_EXTEND);
+    cxJsonWrite(&buf, obj, (cx_write_func)cxBufferWrite, &writer);
+    cxJsonValueFree(obj);
+    cxBufferTerminate(&buf);
+    
+    return buf.space;
+}
+
+static char* linkbutton_get_value(UiLinkButton *link) {
+    const char *label = gtk_button_get_label(GTK_BUTTON(link->widget));
+    const char *uri = linkbutton_get_uri(link);
+    gboolean visited = linkbutton_get_visited(link);
+    return create_linkbutton_jsonvalue(label, uri, TRUE, visited, TRUE);
+}
+
+static void linkbutton_clicked(GtkWidget *widget, UiLinkButton *data) {
+    if(data->onclick) {
+        UiEvent e;
+        e.obj = data->obj;
+        e.document = e.obj->ctx->document;
+        e.window = e.obj->window;
+        e.eventdata = (char*)linkbutton_get_uri(data);
+        e.eventdatatype = UI_EVENT_DATA_STRING;
+        e.intval = 0;
+        e.set = ui_get_setop();
+        data->onclick(&e, data->onclickdata);
+    }
+}
+
+static gboolean linkbutton_activate_link(GtkLinkButton *self, UiLinkButton *data) {
+    linkbutton_clicked(data->widget, data);
+    return data->nofollow;
+}
+
+UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args) {
+    UiLinkButton *data = malloc(sizeof(UiLinkButton));
+    memset(data, 0, sizeof(UiLinkButton));
+    data->obj = obj;
+    data->type = args->type;
+    data->nofollow = args->nofollow;
+    data->onclick = args->onclick;
+    data->onclickdata = args->onclickdata;
+    
+    GtkWidget *button;
+    if(args->type == UI_LINK_BUTTON) {
+        button = gtk_button_new();
+        g_signal_connect(
+                button,
+                "clicked",
+                G_CALLBACK(linkbutton_clicked),
+                data);
+    } else {
+        button = gtk_link_button_new("file:///");
+        g_signal_connect(
+                button,
+                "activate-link",
+                G_CALLBACK(linkbutton_activate_link),
+                data);
+    }
+    gtk_button_set_label(GTK_BUTTON(button), args->label);
+    g_object_set_data(G_OBJECT(button), "ui_linkbutton", data);
+    g_signal_connect(
+            button,
+            "destroy",
+            G_CALLBACK(ui_destroy_linkbutton),
+            data);
+    
+    data->widget = button;
+    
+    UiObject* current = uic_current_obj(obj);
+    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    if(var) {
+        UiString *str = var->value;
+        char *current_value = ui_get(str);
+        if(current_value) {
+            linkbutton_apply_value(data, current_value);
+        }
+        
+        str->obj = data;
+        str->get = ui_linkbutton_get;
+        str->set = ui_linkbutton_set;
+    }
+    
+    ui_set_name_and_style(button, args->name, args->style_class);
+    ui_set_widget_groups(obj->ctx, button, args->groups);
+    UI_APPLY_LAYOUT2(current, args);
+    current->container->add(current->container, button);
+    
+    return button;
+}
+
+char* ui_linkbutton_get(UiString *s) {
+    UiLinkButton *link = s->obj;
+    if(s->value.free) {
+        s->value.free(s->value.ptr);
+    }
+    s->value.ptr = linkbutton_get_value(link);
+    s->value.free = free;
+    return s->value.ptr;
+}
+
+void ui_linkbutton_set(UiString *s, const char *str) {
+    linkbutton_apply_value(s->obj, str);
+    if(s->value.free) {
+        s->value.free(s->value.ptr);
+    }
+}
+
+
+void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri) {
+    char *value = create_linkbutton_jsonvalue(label, uri, TRUE, FALSE, TRUE);
+    ui_set(str, value);
+    free(value);
+}
+
+void ui_linkbutton_value_set_label(UiString *str, const char *label) {
+    char *value = create_linkbutton_jsonvalue(label, NULL, FALSE, FALSE, TRUE);
+    ui_set(str, value);
+    free(value);
+}
+
+void ui_linkbutton_value_set_uri(UiString *str, const char *uri) {
+    char *value = create_linkbutton_jsonvalue(NULL, uri, FALSE, FALSE, TRUE);
+    ui_set(str, value);
+    free(value);
+}
+
+void ui_linkbutton_value_set_visited(UiString *str, UiBool visited) {
+    char *value = create_linkbutton_jsonvalue(NULL, NULL, FALSE, visited, TRUE);
+    ui_set(str, value);
+    free(value);
+}
+
+
+void ui_linkbutton_set_label(UIWIDGET button, const char *label) {
+    gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_linkbutton_set_uri(UIWIDGET button, const char *label) {
+    UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+    if(link) {
+        linkbutton_set_uri(link, label);
+    } else {
+        fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+    }
+}
+
+void ui_linkbutton_set_visited(UIWIDGET button, UiBool visited) {
+    UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+    if(link) {
+        linkbutton_set_visited(link, visited);
+    } else {
+        fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+    }
+}
+
+char* ui_linkbutton_get_label(UIWIDGET button) {
+    const char *label = gtk_button_get_label(GTK_BUTTON(button));
+    return label ? strdup(label) : NULL;
+}
+
+char* ui_linkbutton_get_uri(UIWIDGET button) {
+    UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+    if(link) {
+        const char *uri = linkbutton_get_uri(link);
+        return uri ? strdup(uri) : NULL;
+    } else {
+        fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+    }
+    return NULL;
+}
+
+UiBool ui_linkbutton_get_visited(UIWIDGET button) {
+    UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+    if(link) {
+        return linkbutton_get_visited(link);
+    } else {
+        fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+    }
+    return FALSE;
+}

mercurial