]> uap-core.de Git - mizunara.git/commitdiff
implement filelist onaction event
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 8 Jul 2026 18:08:37 +0000 (20:08 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 8 Jul 2026 18:08:37 +0000 (20:08 +0200)
63 files changed:
mizunara/application.h
mizunara/filebrowser.c
mizunara/window.c
mizunara/window.h
ui/Makefile
ui/common/Makefile [new file with mode: 0644]
ui/common/action.c [new file with mode: 0644]
ui/common/action.h [new file with mode: 0644]
ui/common/app.c
ui/common/app.h
ui/common/args.c
ui/common/args.h
ui/common/container.c
ui/common/context.c
ui/common/context.h
ui/common/document.c
ui/common/icons.c [new file with mode: 0644]
ui/common/icons.h [new file with mode: 0644]
ui/common/menu.c
ui/common/menu.h
ui/common/object.c
ui/common/object.h
ui/common/objs.mk
ui/common/toolbar.c
ui/common/toolbar.h
ui/common/types.c
ui/common/types.h
ui/common/ucx_properties.c [deleted file]
ui/common/ucx_properties.h [deleted file]
ui/common/wrapper.c
ui/common/wrapper.h
ui/gtk/Makefile
ui/gtk/action.c [new file with mode: 0644]
ui/gtk/action.h [new file with mode: 0644]
ui/gtk/button.c
ui/gtk/button.h
ui/gtk/container.c
ui/gtk/container.h
ui/gtk/headerbar.c
ui/gtk/headerbar.h
ui/gtk/icon.c
ui/gtk/list.c
ui/gtk/list.h
ui/gtk/menu.c
ui/gtk/menu.h
ui/gtk/objs.mk
ui/gtk/text.c
ui/gtk/text.h
ui/gtk/toolbar.c
ui/gtk/toolbar.h
ui/gtk/toolkit.c
ui/gtk/toolkit.h
ui/gtk/window.c
ui/gtk/window.h [new file with mode: 0644]
ui/ui/button.h
ui/ui/container.h
ui/ui/icons.h
ui/ui/list.h
ui/ui/menu.h
ui/ui/text.h
ui/ui/toolbar.h
ui/ui/toolkit.h
ui/ui/widget.h

index 9a341012c62b4154b066105ea348e4def872b705..b16abfcd3907bc2955c52fbafd452ad2583613fc 100644 (file)
@@ -118,8 +118,10 @@ struct FileBrowser {
     
     /*
      * file listview list
+     * type: FileInfo*
      */
     UiList *list_files;
+    char *list_files_parent;
 };
 
 /*
index 9ec345bca55fdc53ba37de5872344f891b3ecb30..51603fa91242a1a881e94052a413212d13aff473 100644 (file)
@@ -157,14 +157,16 @@ void filebrowser_op_finished(UiEvent *event, void *data) {
             }
             
         } else if(view == 1) {
+            free(browser->list_files_parent);
             ui_list_clear(browser->list_files);
             CxIterator i = cxListIterator(op->result);
             cx_foreach(FileInfo *, file, i) {
                 ui_list_append(browser->list_files, file);
             }
+            browser->list_files_parent = op->url;
+            op->url = NULL;
             ui_list_update(browser->list_files);
             op->result = NULL;
-            // TODO: url?
         }
     } else {
         // TODO: error msg
index 3984cb75f03067d2e2c73f0cbfb63a73734fdebe..9ff4f6781a09adb237def280ae7832a555299a53 100644 (file)
@@ -163,6 +163,7 @@ void window_create_browser_view(UiObject *obj, MainWindow *win) {
                     .varname = "list_files",
                     .getvalue2 = window_filelistview_getvalue,
                     .getstyle = window_filelistview_getstyle,
+                    .onactivate = window_filelistview_onactivate,
                     .fill = TRUE);
         }
     }
@@ -192,6 +193,19 @@ void window_sidebar_user_dirs_item(UiList *list, void *sublist_userdata, void *r
     item->label = strdup(bookmark->name);
 }
 
+void window_filelistview_onactivate(UiEvent *event, void *userdata) {
+    MainWindow *window = event->window;
+    FileBrowser *browser = event->document;
+    if(event->eventdatatype != UI_EVENT_DATA_LIST_SELECTION) {
+        return;
+    }
+    
+    UiListSelection *sel = event->eventdata;
+    if(sel->count == 1) {
+        FileInfo *file = ui_list_get(browser->list_files, sel->rows[0]);
+        open_files(&file, 1, window);
+    }
+}
 
 void* window_filelistview_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
     FileInfo *file = elm;
index 518e5cb00e41ca9b5d8b019cd55be425e05c38fd..b18c13f2c973ec6177a66ea12a7c0b1e92b9a33b 100644 (file)
@@ -45,6 +45,8 @@ void window_sidebar_getvalue(UiList *list, void *sublist_userdata, void *rowdata
 
 void window_sidebar_user_dirs_item(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
 
+void window_filelistview_onactivate(UiEvent *event, void *userdata);
+
 void* window_filelistview_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult);
 UiBool window_filelistview_getstyle(UiList *list, void *elm, int row, int col, void *userdata, UiTextStyle *style);
 
index ad5aad0f563cbf93f8b7de3d6e7ed169a9abf4a8..b03b6d3d1ad64d8e2c1b7d0cf948b077aeecdb34 100644 (file)
@@ -41,8 +41,5 @@ OBJ = $(TOOLKITOBJS) $(COMMONOBJS)
 
 all: $(UI_LIB) $(UI_SHLIB)
 
+include common/Makefile
 include $(TOOLKIT)/Makefile
-
-$(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c
-       $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
-
diff --git a/ui/common/Makefile b/ui/common/Makefile
new file mode 100644 (file)
index 0000000..703da14
--- /dev/null
@@ -0,0 +1,111 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Olaf Wintermann. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   1. Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above copyright
+#      notice, this list of conditions and the following disclaimer in the
+#      documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+FORCE:
+
+$(COMMON_OBJPRE)uic_action$(OBJ_EXT): common/action.c common/action.h \
+ common/../ui/toolkit.h common/context.h common/object.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_app$(OBJ_EXT): common/app.c common/app.h \
+ common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_args$(OBJ_EXT): common/args.c common/args.h \
+ common/../ui/window.h common/../ui/toolkit.h common/../ui/container.h \
+ common/../ui/display.h common/../ui/button.h common/../ui/entry.h \
+ common/../ui/menu.h common/../ui/toolbar.h common/../ui/list.h \
+ common/../ui/text.h common/../ui/webview.h common/../ui/widget.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_condvar$(OBJ_EXT): common/condvar.c common/condvar.h \
+ common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_container$(OBJ_EXT): common/container.c \
+ common/container.h common/../ui/container.h common/../ui/toolkit.h \
+ common/object.h common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_context$(OBJ_EXT): common/context.c common/context.h \
+ common/../ui/toolkit.h common/action.h common/../ui/window.h \
+ common/../ui/toolkit.h common/../ui/widget.h common/document.h \
+ common/types.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_document$(OBJ_EXT): common/document.c \
+ common/document.h common/../ui/toolkit.h common/context.h \
+ common/action.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_icons$(OBJ_EXT): common/icons.c common/icons.h \
+ common/../ui/icons.h common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_menu$(OBJ_EXT): common/menu.c common/menu.h \
+ common/../ui/menu.h common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_message$(OBJ_EXT): common/message.c common/message.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_object$(OBJ_EXT): common/object.c common/object.h \
+ common/../ui/toolkit.h common/context.h common/action.h \
+ common/../ui/container.h common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_properties$(OBJ_EXT): common/properties.c \
+ common/../ui/toolkit.h common/properties.h common/../ui/properties.h \
+ common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_threadpool$(OBJ_EXT): common/threadpool.c \
+ common/threadpool.h common/../ui/toolkit.h common/context.h \
+ common/action.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_toolbar$(OBJ_EXT): common/toolbar.c common/toolbar.h \
+ common/../ui/toolbar.h common/../ui/toolkit.h common/menu.h \
+ common/../ui/menu.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_types$(OBJ_EXT): common/types.c common/../ui/list.h \
+ common/../ui/toolkit.h common/types.h common/../ui/toolkit.h \
+ common/context.h common/action.h common/../ui/image.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_utils$(OBJ_EXT): common/utils.c common/utils.h \
+ common/../ui/toolkit.h common/../ui/text.h common/../ui/toolkit.h \
+ common/properties.h common/../ui/properties.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(COMMON_OBJPRE)uic_wrapper$(OBJ_EXT): common/wrapper.c common/wrapper.h \
+ common/../ui/toolkit.h common/../ui/list.h common/../ui/toolkit.h \
+ common/../ui/text.h common/types.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
diff --git a/ui/common/action.c b/ui/common/action.c
new file mode 100644 (file)
index 0000000..683ed37
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "action.h"
+#include "context.h"
+#include "object.h"
+
+#include <cx/string.h>
+
+void uic_add_action(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text)
+{
+    if(!name) {
+        return;
+    }
+    
+    UiAction action;
+    action.name = ui_strdup(ctx, name);
+    action.callback = callback;
+    action.userdata = userdata;
+    action.accelerator = accelerator ? ui_strdup(ctx, accelerator) : NULL;
+    action.accelerator_text = accelerator_text ? ui_strdup(ctx, accelerator_text) : NULL;
+    action.ctx = ctx;
+    cxMapPut(ctx->actions, name, &action);
+    cxMapRehash(ctx->actions);
+}
+
+void uic_bind_action(
+        UiContext *ctx,
+        const char *action,
+        void *bind_obj,
+        ui_enablefunc set_enabled)
+{
+    if(!action) {
+        return;
+    }
+    
+    UiActionBinding binding;
+    binding.action = ui_strdup(ctx, action);
+    binding.userdata = bind_obj;
+    binding.set_enabled = set_enabled;
+    cxListAdd(ctx->action_bindings, &binding);
+}
+
+UiAction* uic_resolve_action(UiContext *ctx, const char *action) {
+    UiAction *a = NULL;
+    if(ctx->actions) {
+        a = cxMapGet(ctx->actions, action);
+    }
+    // check if any sub-document defines this action
+    // sub-document actions have precedence, the most specific action will
+    // be returned
+    CxIterator i = cxListIterator(ctx->documents);
+    cx_foreach(void *, doc, i) {
+        UiContext *doc_ctx = ui_document_context(doc);
+        UiAction *sub_action = uic_resolve_action(doc_ctx, action);
+        if(sub_action) {
+            a = sub_action;
+            // if one sub-tree has an action, we don't care about other
+            // subtrees
+            break;
+        }
+    }
+    
+    if(!a && ctx->parent) {
+        // check parents
+        a = uic_resolve_action_from_parents(ctx, action);
+    }
+    
+    return a;
+}
+
+UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action) {
+    UiContext *parent = ctx->parent;
+    if(parent == NULL) {
+        return NULL;
+    }
+    if(parent->actions) {
+        UiAction *a = cxMapGet(parent->actions, action);
+        if(a) {
+            return a;
+        }
+    }
+    return uic_resolve_action_from_parents(parent, action);
+}
+
+
+
+void ui_update_action_bindings(UiContext *ctx) {
+    CxIterator i = cxListIterator(ctx->action_bindings);
+    cx_foreach(UiActionBinding*, binding, i) {
+        UiAction *action = uic_resolve_action(ctx, binding->action);
+        if(binding->set_enabled) {
+            binding->set_enabled(binding->userdata, action != NULL);
+        }
+    }
+}
+
+void uic_action_callback(UiEvent *event, const char *action_name) {
+    UiContext *ctx = ui_global_context();
+    if(event->obj) {
+        ctx = event->obj->ctx;
+    }
+    
+    UiAction *action = uic_resolve_action(ctx, action_name);
+    if(action) {
+        // override event document: for actions we know that the event is
+        // for a specific document
+        event->document = action->ctx->self_doc;
+        if(action->callback) {
+            action->callback(event, action->userdata);
+        }
+    }
+}
+
+static int call_action(UiContext *ctx, const char *action_name, void *eventdata, UiEventType eventdatatype, int intval) {
+    UiAction *action = uic_resolve_action(ctx, action_name);
+    if(action && action->callback) {
+        UiEvent event;
+        memset(&event, 0, sizeof(UiEvent));
+        event.obj = ctx->obj;
+        event.window = event.obj ? event.obj->window : NULL;
+        event.document = ctx->self_doc ? ctx->self_doc : ctx->document;
+        if(eventdata) {
+            event.eventdata = eventdata;
+            event.eventdatatype = eventdatatype;
+        }
+        event.intval = intval;
+        action->callback(&event, action->userdata);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+int ui_call_action(UiContext *ctx, const char *action_name) {
+    return ui_call_action2(ctx, action_name, NULL, 0);
+}
+
+int ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval) {
+    return call_action(ctx, action_name, eventdata, UI_EVENT_DATA_POINTER, intval);
+}
+
+int ui_call_action3(UiContext *ctx, const char *action_name, void *ptr, uint64_t type_id) {
+    UiTypedObj *obj = malloc(sizeof(UiTypedObj));
+    obj->ptr = ptr;
+    obj->type = type_id;
+    int ret = call_action(ctx, action_name, obj, UI_EVENT_DATA_TYPED_OBJECT, 0);
+    free(obj);
+    return ret;
+}
+
+static void call_action_recursive(const char *action_name, UiContext *ctx, void *eventdata, UiEventType eventdatatype, int intval, UiBool call_children) {
+    UiEvent event;
+    memset(&event, 0, sizeof(UiEvent));
+    event.obj = ctx->obj;
+    event.window = event.obj ? event.obj->window : NULL;
+    event.document = ctx->self_doc ? ctx->self_doc : ctx->document;
+    if(eventdata) {
+        event.eventdata = eventdata;
+        event.eventdatatype = eventdatatype;
+    }
+    event.intval = intval;
+    
+    UiAction *a = NULL;
+    if(ctx->actions) {
+        a = cxMapGet(ctx->actions, action_name);
+    }
+    if(a && a->callback) {
+        a->callback(&event, a->userdata);
+    }
+    
+    if(call_children) {
+        CxIterator i = cxListIterator(ctx->documents);
+        cx_foreach(void *, doc, i) {
+            UiContext *doc_ctx = ui_document_context(doc);
+            call_action_recursive(action_name, doc_ctx, eventdata, eventdatatype, intval, TRUE);
+        }
+    }
+}
+
+static void broadcast_action(const char *action_name, void *eventdata, UiEventType eventdatatype, int intval) {
+    CxList *objects = uic_object_list();
+    CxIterator i = cxListIterator(objects);
+    cx_foreach(UiObject*, obj, i) {
+        call_action_recursive(action_name, obj->ctx, eventdata, eventdatatype, intval, TRUE);
+    }
+    
+    call_action_recursive(action_name, ui_global_context(), eventdata, eventdatatype, intval, FALSE);
+}
+
+void ui_broadcast_action(const char *action_name) {
+    broadcast_action(action_name, NULL, UI_EVENT_DATA_NULL, 0);
+}
+
+void ui_broadcast_action2(const char *action_name, void *eventdata, int intval) {
+    broadcast_action(action_name, eventdata, UI_EVENT_DATA_POINTER, intval);
+}
+
+void ui_call_action_on(UiContext *ctx, const char *action) {
+    UiEvent event;
+    memset(&event, 0, sizeof(UiEvent));
+    event.obj = ctx->obj;
+    event.window = event.obj ? event.obj->window : NULL;
+    event.document = ctx->self_doc ? ctx->self_doc : ctx->document;
+    
+    UiAction *a = NULL;
+    if(ctx->actions) {
+        a = cxMapGet(ctx->actions, action);
+    }
+    if(a && a->callback) {
+        a->callback(&event, a->userdata);
+    }
+}
+
+typedef struct UiActionBroadcast {
+    char *action;
+    void *eventdata;
+    UiEventType eventdatataype;
+    int intval;
+} UiActionBroadcast;
+
+void ui_mainthread_broadcast(const char *action_name) {
+    ui_mainthread_broadcast2(action_name, NULL, 0);
+}
+
+static int mainthread_action_broadcast(void *data) {
+    UiActionBroadcast *broadcast = data;
+    broadcast_action(broadcast->action, broadcast->eventdata, broadcast->eventdatataype, broadcast->intval);
+    if(broadcast->eventdatataype == UI_EVENT_DATA_TYPED_OBJECT) {
+        free(broadcast->eventdata);
+    }
+    free(broadcast->action);
+    free(broadcast);
+    return 0;
+}
+
+void ui_mainthread_broadcast2(const char *action_name, void *eventdata, int intval) {
+    UiActionBroadcast *broadcast = malloc(sizeof(UiActionBroadcast));
+    broadcast->action = strdup(action_name);
+    broadcast->eventdata = eventdata;
+    broadcast->eventdatataype = UI_EVENT_DATA_POINTER;
+    broadcast->intval = intval;
+    ui_call_mainthread(mainthread_action_broadcast, broadcast);
+}
+
+void ui_mainthread_broadcast3(const char *action_name, void *ptr, uint64_t type_id) {
+    UiTypedObj *obj = malloc(sizeof(UiTypedObj));
+    obj->ptr = ptr;
+    obj->type = type_id;
+    
+    UiActionBroadcast *broadcast = malloc(sizeof(UiActionBroadcast));
+    broadcast->action = strdup(action_name);
+    broadcast->eventdata = obj;
+    broadcast->eventdatataype = UI_EVENT_DATA_TYPED_OBJECT;
+    broadcast->intval = 0;
+    ui_call_mainthread(mainthread_action_broadcast, broadcast);
+}
diff --git a/ui/common/action.h b/ui/common/action.h
new file mode 100644 (file)
index 0000000..1364635
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_ACTION_H
+#define UIC_ACTION_H
+
+#include "../ui/toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct UiAction        UiAction;
+typedef struct UiActionBinding UiActionBinding;
+
+struct UiAction {
+    char *name;
+    char *accelerator;
+    char *accelerator_text;
+    ui_callback callback;
+    void *userdata;
+    UiContext *ctx;
+};
+
+struct UiActionBinding {
+    const char *action;
+    ui_enablefunc set_enabled;
+    void *userdata;
+};
+
+void uic_add_action(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text);
+
+void uic_bind_action(
+        UiContext *ctx,
+        const char *action,
+        void *bind_obj,
+        ui_enablefunc set_enabled);
+
+UiAction* uic_resolve_action(UiContext *ctx, const char *action);
+UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action);
+
+// action event wrapper
+void uic_action_callback(UiEvent *event, const char *action_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_ACTION_H */
+
index 9674599fdd794e92a54da6e8405ef0a70425d078..c7f80decaa2438a7c40533e382c8f0697036e81c 100644 (file)
@@ -30,6 +30,8 @@
 
 static ui_callback   startup_func;
 static void          *startup_data;
+static ui_callback   newwindow_func;
+static void          *newwindow_data;
 static ui_callback   open_func;
 void                 *open_data;
 static ui_callback   exit_func;
@@ -41,6 +43,11 @@ void ui_onstartup(ui_callback f, void *userdata) {
     startup_data = userdata;
 }
 
+void ui_onnewwindow(ui_callback f, void *userdata) {
+    newwindow_func = f;
+    newwindow_data = userdata;
+}
+
 void ui_onopen(ui_callback f, void *userdata) {
     open_func = f;
     open_data = userdata;
@@ -51,13 +58,18 @@ void ui_onexit(ui_callback f, void *userdata) {
     exit_data = userdata;
 }
 
-
 void uic_application_startup(UiEvent *event) {
     if(startup_func) {
         startup_func(event, startup_data);
     }
 }
 
+void uic_application_newwindow(UiEvent *event) {
+    if(newwindow_func) {
+        newwindow_func(event, newwindow_data);
+    }
+}
+
 void uic_application_open(UiEvent *event) {
     if(open_func) {
         open_func(event, open_data);
@@ -69,3 +81,7 @@ void uic_application_exit(UiEvent *event) {
         exit_func(event, exit_data);
     }
 }
+
+void ui_newwindow(void) {
+    uic_application_newwindow(NULL);
+}
index 02356a916e5fcc3e96d85b51e59bff838a32555b..9176e85f8f99e2466e9c8a068835cf41accea6d8 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 #endif
 
 void uic_application_startup(UiEvent *event);
+void uic_application_newwindow(UiEvent *event);
 void uic_application_open(UiEvent *event);
 void uic_application_exit(UiEvent *event);
 
index 821b2215197ebce84d446da3e53e8cb181df62b2..8c1e2b4027c13f9dbee4d61c17a0ae8493c64681 100644 (file)
@@ -215,9 +215,14 @@ void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) {
     args->onclickdata = onclickdata;
 }
 
+void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_menuitem_args_free(UiMenuItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
+    free((void*)args->action);
     free(args);
 }
 
@@ -250,10 +255,15 @@ void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *o
     args->onchangedata = onclickdata;
 }
 
+void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->varname);
+    free((void*)args->action);
     free(args);
 }
 
@@ -273,6 +283,14 @@ void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc
     args->getvalue = func;
 }
 
+void ui_menuitemlist_args_set_getvalue2(UiMenuItemListArgs *args, ui_getvaluefunc2 func) {
+    args->getvalue2 = func;
+}
+
+void ui_menuitemlist_args_set_getvaluedata(UiMenuItemListArgs *args, void *data) {
+    args->getvaluedata = data;
+}
+
 void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback) {
     args->onselect = callback;
 }
@@ -310,6 +328,10 @@ void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *toolt
     args->tooltip = strdup(tooltip);
 }
 
+void ui_toolbar_item_args_set_action(UiToolbarItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback) {
     args->onclick = callback;
 }
@@ -327,6 +349,7 @@ void ui_toolbar_item_args_free(UiToolbarItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->tooltip);
+    free((void*)args->action);
     free((void*)args->states);
     free(args);
 }
@@ -355,6 +378,10 @@ void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const
     args->varname = strdup(varname);
 }
 
+void ui_toolbar_toggleitem_args_set_action(UiToolbarToggleItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback) {
     args->onchange = callback;
 }
@@ -374,6 +401,82 @@ void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
     free((void*)args->icon);
     free((void*)args->tooltip);
     free((void*)args->varname);
+    free((void*)args->action);
+    free((void*)args->states);
+    free(args);
+}
+
+/* ---------------------------- UiToolbarContentToggleItemArgs ---------------------------- */
+
+UiToolbarContentToggleItemArgs* ui_toolbar_content_toggleitem_args_new(void) {
+    UiToolbarContentToggleItemArgs *args = malloc(sizeof(UiToolbarContentToggleItemArgs));
+    memset(args, 0, sizeof(UiToolbarContentToggleItemArgs));
+    return args;
+}
+
+void ui_toolbar_content_toggleitem_args_set_label0(UiToolbarContentToggleItemArgs *args, const char *label) {
+    args->label0 = strdup(label);
+}
+
+void ui_toolbar_content_toggleitem_args_set_icon0(UiToolbarContentToggleItemArgs *args, const char *icon) {
+    args->icon0 = strdup(icon);
+}
+
+void ui_toolbar_content_toggleitem_args_set_tooltip0(UiToolbarContentToggleItemArgs *args, const char *tooltip) {
+    args->tooltip0 = strdup(tooltip);
+}
+
+void ui_toolbar_content_toggleitem_args_set_label1(UiToolbarContentToggleItemArgs *args, const char *label) {
+    args->label1 = strdup(label);
+}
+
+void ui_toolbar_content_toggleitem_args_set_icon1(UiToolbarContentToggleItemArgs *args, const char *icon) {
+    args->icon1 = strdup(icon);
+}
+
+void ui_toolbar_content_toggleitem_args_set_tooltip1(UiToolbarContentToggleItemArgs *args, const char *tooltip) {
+    args->tooltip1 = strdup(tooltip);
+}
+
+void ui_toolbar_content_toggleitem_args_set_varname(UiToolbarContentToggleItemArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_toolbar_content_toggleitem_args_set_action(UiToolbarContentToggleItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
+void ui_toolbar_content_toggleitem_args_set_onchange(UiToolbarContentToggleItemArgs *args, ui_callback callback) {
+    args->onchange = callback;
+}
+
+void ui_toolbar_content_toggleitem_args_set_onchangedata(UiToolbarContentToggleItemArgs *args, void *onchangedata) {
+    args->onchangedata = onchangedata;
+}
+
+void ui_toolbar_content_toggleitem_args_set_istogglebutton(UiToolbarContentToggleItemArgs *args, UiBool value) {
+    args->istogglebutton = value;
+}
+
+void ui_toolbar_content_toggleitem_args_set_toggled_by_state(UiToolbarContentToggleItemArgs *args, int state) {
+    args->toggled_by_state = state;
+}
+
+void ui_toolbar_content_toggleitem_args_set_states(UiToolbarContentToggleItemArgs *args,int *states, int numstates) {
+    args->states = calloc(numstates+1, sizeof(int));
+    memcpy((void*)args->states, states, numstates * sizeof(int));
+    ((int*)args->states)[numstates] = -1;
+}
+
+void ui_toolbar_content_toggleitem_args_free(UiToolbarContentToggleItemArgs *args) {
+    free((void*)args->label0);
+    free((void*)args->icon0);
+    free((void*)args->tooltip0);
+    free((void*)args->label1);
+    free((void*)args->icon1);
+    free((void*)args->tooltip1);
+    free((void*)args->varname);
+    free((void*)args->action);
     free((void*)args->states);
     free(args);
 }
@@ -1440,6 +1543,10 @@ void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
     args->onclickdata = onclickdata;
 }
 
+void ui_button_args_set_action(UiButtonArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates) {
     args->states = calloc(numstates+1, sizeof(int));
     memcpy((void*)args->states, states, numstates * sizeof(int));
@@ -1458,6 +1565,7 @@ void ui_button_args_free(UiButtonArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->tooltip);
+    free((void*)args->action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
@@ -1558,6 +1666,10 @@ void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
     args->onchangedata = onchangedata;
 }
 
+void ui_toggle_args_set_action(UiToggleArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
     args->varname = strdup(varname);
 }
@@ -1589,6 +1701,165 @@ void ui_toggle_args_free(UiToggleArgs *args) {
     free((void*)args->icon);
     free((void*)args->tooltip);
     free((void*)args->varname);
+    free((void*)args->action);
+    free((void*)args->states);
+    free((void*)args->visibility_states);
+    free(args);
+}
+
+/* ------------------------- UiContentToggleArgs ----------------------------*/
+
+
+UiContentToggleArgs* ui_content_toggle_args_new(void) {
+    UiContentToggleArgs *args = malloc(sizeof(UiContentToggleArgs));
+    memset(args, 0, sizeof(UiContentToggleArgs));
+    return args;
+}
+
+void ui_content_toggle_args_set_fill(UiContentToggleArgs *args, UiBool fill) {
+    args->fill = fill;
+}
+
+void ui_content_toggle_args_set_hexpand(UiContentToggleArgs *args, UiBool value) {
+    args->hexpand = value;
+}
+
+void ui_content_toggle_args_set_vexpand(UiContentToggleArgs *args, UiBool value) {
+    args->vexpand = value;
+}
+
+void ui_content_toggle_args_set_hfill(UiContentToggleArgs *args, UiBool value) {
+    args->hfill = value;
+}
+
+void ui_content_toggle_args_set_vfill(UiContentToggleArgs *args, UiBool value) {
+    args->vfill = value;
+}
+
+void ui_content_toggle_args_set_override_defaults(UiContentToggleArgs *args, UiBool value) {
+    args->override_defaults = value;
+}
+
+void ui_content_toggle_args_set_margin(UiContentToggleArgs *args, int value) {
+    args->margin = value;
+}
+
+void ui_content_toggle_args_set_margin_left(UiContentToggleArgs *args, int value) {
+    args->margin_left = value;
+}
+
+void ui_content_toggle_args_set_margin_right(UiContentToggleArgs *args, int value) {
+    args->margin_right = value;
+}
+
+void ui_content_toggle_args_set_margin_top(UiContentToggleArgs *args, int value) {
+    args->margin_top = value;
+}
+
+void ui_content_toggle_args_set_margin_bottom(UiContentToggleArgs *args, int value) {
+    args->margin_bottom = value;
+}
+
+void ui_content_toggle_args_set_colspan(UiContentToggleArgs *args, int colspan) {
+    args->colspan = colspan;
+}
+
+void ui_content_toggle_args_set_rowspan(UiContentToggleArgs *args, int rowspan) {
+    args->rowspan = rowspan;
+}
+
+
+void ui_content_toggle_args_set_name(UiContentToggleArgs *args, const char *name) {
+    args->name = strdup(name);
+}
+
+void ui_content_toggle_args_set_style_class(UiContentToggleArgs *args, const char *classname) {
+    args->style_class = strdup(classname);
+}
+
+void ui_content_toggle_args_set_label0(UiContentToggleArgs *args, const char *label){
+    args->label0 = strdup(label);
+}
+
+void ui_content_toggle_args_set_icon0(UiContentToggleArgs *args, const char *icon){
+    args->icon0 = strdup(icon);
+}
+
+void ui_content_toggle_args_set_tooltip0(UiContentToggleArgs *args, const char *tooltip) {
+    args->tooltip0 = strdup(tooltip);
+}
+
+void ui_content_toggle_args_set_label1(UiContentToggleArgs *args, const char *label){
+    args->label1 = strdup(label);
+}
+
+void ui_content_toggle_args_set_icon1(UiContentToggleArgs *args, const char *icon){
+    args->icon1 = strdup(icon);
+}
+
+void ui_content_toggle_args_set_tooltip1(UiContentToggleArgs *args, const char *tooltip) {
+    args->tooltip1 = strdup(tooltip);
+}
+
+void ui_content_toggle_args_set_labeltype(UiContentToggleArgs *args, int labeltype){
+    args->labeltype = labeltype;
+}
+
+void ui_content_toggle_args_set_onchange(UiContentToggleArgs *args, ui_callback callback){
+    args->onchange = callback;
+}
+
+void ui_content_toggle_args_set_onchangedata(UiContentToggleArgs *args, void *onchangedata){
+    args->onchangedata = onchangedata;
+}
+
+void ui_content_toggle_args_set_action(UiContentToggleArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
+void ui_content_toggle_args_set_varname(UiContentToggleArgs *args, const char *varname) {
+    args->varname = strdup(varname);
+}
+
+void ui_content_toggle_args_set_value(UiContentToggleArgs *args, UiInteger *value) {
+    args->value = value;
+}
+
+void ui_content_toggle_args_set_toggled_by_state(UiContentToggleArgs *args, int state) {
+    args->toggled_by_state = state;
+}
+
+void ui_content_toggle_args_set_istogglebutton(UiContentToggleArgs *args, UiBool value) {
+    args->istogglebutton = value;
+}
+
+void ui_content_toggle_args_set_enablestate(UiContentToggleArgs *args, int state) {
+    args->enable_state = state;
+}
+
+void ui_content_toggle_args_set_states(UiContentToggleArgs *args, int *states, int numstates) {
+    args->states = calloc(numstates+1, sizeof(int));
+    memcpy((void*)args->states, states, numstates * sizeof(int));
+    ((int*)args->states)[numstates] = -1;
+}
+
+void ui_content_toggle_args_set_visibility_states(UiContentToggleArgs *args, int *states, int numstates) {
+    args->visibility_states = calloc(numstates+1, sizeof(int));
+    memcpy((void*)args->visibility_states, states, numstates * sizeof(int));
+    ((int*)args->visibility_states)[numstates] = -1;
+}
+
+void ui_content_toggle_args_free(UiContentToggleArgs *args) {
+    free((void*)args->name);
+    free((void*)args->style_class);
+    free((void*)args->label0);
+    free((void*)args->icon0);
+    free((void*)args->tooltip0);
+    free((void*)args->label1);
+    free((void*)args->icon1);
+    free((void*)args->tooltip1);
+    free((void*)args->varname);
+    free((void*)args->action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
@@ -1688,6 +1959,10 @@ void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata)
     args->onclickdata = userdata;
 }
 
+void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value) {
     args->nofollow = value;
 }
@@ -1721,6 +1996,7 @@ void ui_linkbutton_args_free(UiLinkButtonArgs *args) {
     free((void*)args->style_class);
     free((void*)args->label);
     free((void*)args->uri);
+    free((void*)args->action);
     free((void*)args->varname);
     free((void*)args->states);
     free(args);
@@ -1844,6 +2120,10 @@ void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata) {
     args->onactivatedata = userdata;
 }
 
+void ui_list_args_set_onactivate_action(UiListArgs *args, const char *action) {
+    args->onactivate_action = strdup(action);
+}
+
 void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback) {
     args->onselection = callback;
 }
@@ -1852,6 +2132,10 @@ void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata) {
     args->onselectiondata = userdata;
 }
 
+void ui_list_args_set_onselection_action(UiListArgs *args, const char *action) {
+    args->onselection_action = strdup(action);
+}
+
 void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback) {
     args->ondragstart = callback;
 }
@@ -1860,6 +2144,10 @@ void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata) {
     args->ondragstartdata = userdata;
 }
 
+void ui_list_args_set_ondragstart_action(UiListArgs *args, const char *action) {
+    args->ondragstart_action = strdup(action);
+}
+
 void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback) {
     args->ondragcomplete = callback;
 }
@@ -1868,6 +2156,10 @@ void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata) {
     args->ondragcompletedata = userdata;
 }
 
+void ui_list_args_set_ondragcomplete_action(UiListArgs *args, const char *action) {
+    args->ondragcomplete_action = strdup(action);
+}
+
 void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback) {
     args->ondrop = callback;
 }
@@ -1876,6 +2168,10 @@ void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata) {
     args->ondropdata = userdata;
 }
 
+void ui_list_args_set_ondrop_action(UiListArgs *args, const char *action) {
+    args->ondrop_action = strdup(action);
+}
+
 void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave) {
     args->onsave = onsave;
 }
@@ -1908,6 +2204,11 @@ void ui_list_args_free(UiListArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
+    free((void*)args->onactivate_action);
+    free((void*)args->onselection_action);
+    free((void*)args->ondragstart_action);
+    free((void*)args->ondragcomplete_action);
+    free((void*)args->ondrop_action);
     if(args->static_elements) {
         for(int i=0;i<args->static_nelm;i++) {
             free(args->static_elements[i]);
@@ -2049,6 +2350,12 @@ void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value)
     args->header_is_item = value;
 }
 
+UIEXPORT void ui_sourcelist_args_set_states(UiSourceListArgs *args, int *states, int numstates) {
+    args->visibility_states = calloc(numstates+1, sizeof(int));
+    memcpy((void*)args->states, states, numstates * sizeof(int));
+    ((int*)args->states)[numstates] = -1;
+}
+
 void ui_sourcelist_args_set_visibility_states(UiSourceListArgs *args, int *states, int numstates) {
     args->visibility_states = calloc(numstates+1, sizeof(int));
     memcpy((void*)args->visibility_states, states, numstates * sizeof(int));
@@ -2153,6 +2460,22 @@ void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata)
     args->onchangedata = onchangedata;
 }
 
+void ui_textarea_args_set_onchange_action(UiTextAreaArgs *args, const char *action) {
+    args->onchange_action = strdup(action);
+}
+
+void ui_textarea_args_set_ontextchanged(UiTextAreaArgs *args, ui_callback callback) {
+    args->ontextchanged = callback;
+}
+
+void ui_textarea_args_set_ontextchangeddata(UiTextAreaArgs *args, void *onchangedata) {
+    args->ontextchangeddata = onchangedata;
+}
+
+void ui_textarea_args_set_ontextchanged_action(UiTextAreaArgs *args, const char *action) {
+    args->ontextchanged_action = strdup(action);
+}
+
 void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname) {
     args->varname = strdup(varname);
 }
@@ -2177,6 +2500,8 @@ void ui_textarea_args_free(UiTextAreaArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
+    free((void*)args->onchange_action);
+    free((void*)args->ontextchanged_action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
@@ -2280,6 +2605,14 @@ void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivat
     args->onactivatedata = onactivatedata;
 }
 
+void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action) {
+    args->onactivate_action = strdup(action);
+}
+
+void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action) {
+    args->onchange_action = action;
+}
+
 void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname) {
     args->varname = strdup(varname);
 }
@@ -2304,6 +2637,8 @@ void ui_textfield_args_free(UiTextFieldArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
+    free((void*)args->onactivate_action);
+    free((void*)args->onchange_action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
index 2c5abeb8c1e934951661f103abeb24d949e48144..7a8dbd73025e8521ab2d6bf49e2b57d960dbb3a4 100644 (file)
@@ -83,6 +83,7 @@ UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label
 UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon);
 UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback);
 UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata);
+UIEXPORT void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action);
 UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args);
 
 UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void);
@@ -91,11 +92,14 @@ UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const
 UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname);
 UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback);
 UIEXPORT void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action);
 UIEXPORT void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args);
 
 UIEXPORT UiMenuItemListArgs* ui_menuitemlist_args_new(void);
 UIEXPORT void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname);
 UIEXPORT void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func);
+UIEXPORT void ui_menuitemlist_args_set_getvalue2(UiMenuItemListArgs *args, ui_getvaluefunc2 func);
+UIEXPORT void ui_menuitemlist_args_set_getvaluedata(UiMenuItemListArgs *args, void *data);
 UIEXPORT void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback);
 UIEXPORT void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data);
 UIEXPORT void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value);
@@ -105,6 +109,7 @@ UIEXPORT UiToolbarItemArgs* ui_toolbar_item_args_new(void);
 UIEXPORT void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label);
 UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon);
 UIEXPORT void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip);
+UIEXPORT void ui_toolbar_item_args_set_action(UiToolbarItemArgs *args, const char *action);
 UIEXPORT void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback);
 UIEXPORT void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata);
 UIEXPORT void ui_toolbar_item_args_set_states(UiToolbarItemArgs *args, int *states, int numstates);
@@ -115,11 +120,28 @@ UIEXPORT void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args
 UIEXPORT void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon);
 UIEXPORT void ui_toolbar_toggleitem_args_set_tooltip(UiToolbarToggleItemArgs *args, const char *tooltip);
 UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname);
+UIEXPORT void ui_toolbar_toggleitem_args_set_action(UiToolbarToggleItemArgs *args, const char *action);
 UIEXPORT void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback);
 UIEXPORT void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata);
 UIEXPORT void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *args, int *states, int numstates);
 UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
 
+UIEXPORT UiToolbarContentToggleItemArgs* ui_toolbar_content_toggleitem_args_new(void);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_label0(UiToolbarContentToggleItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_icon0(UiToolbarContentToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_tooltip0(UiToolbarContentToggleItemArgs *args, const char *tooltip);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_label1(UiToolbarContentToggleItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_icon1(UiToolbarContentToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_tooltip1(UiToolbarContentToggleItemArgs *args, const char *tooltip);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_varname(UiToolbarContentToggleItemArgs *args, const char *varname);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_action(UiToolbarContentToggleItemArgs *args, const char *action);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_onchange(UiToolbarContentToggleItemArgs *args, ui_callback callback);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_onchangedata(UiToolbarContentToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_states(UiToolbarContentToggleItemArgs *args, int *states, int numstates);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_istogglebutton(UiToolbarContentToggleItemArgs *args, UiBool value);
+UIEXPORT void ui_toolbar_content_toggleitem_args_set_toggled_by_state(UiToolbarContentToggleItemArgs *args, int state);
+UIEXPORT void ui_toolbar_content_toggleitem_args_free(UiToolbarContentToggleItemArgs *args);
+
 UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
 UIEXPORT void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label);
 UIEXPORT void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon);
@@ -353,6 +375,7 @@ UIEXPORT void ui_button_args_set_tooltip(UiButtonArgs *args, const char *tooltip
 UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype);
 UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback);
 UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata);
+UIEXPORT void ui_button_args_set_action(UiButtonArgs *args, const char *action);
 UIEXPORT void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_button_args_set_visibility_states(UiButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_button_args_free(UiButtonArgs *args);
@@ -379,6 +402,7 @@ UIEXPORT void ui_toggle_args_set_tooltip(UiToggleArgs *args, const char *tooltip
 UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype);
 UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback);
 UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
+UIEXPORT void ui_toggle_args_set_action(UiToggleArgs *args, const char *action);
 UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname);
 UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value);
 UIEXPORT void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state);
@@ -386,6 +410,41 @@ UIEXPORT void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int num
 UIEXPORT void ui_toggle_args_set_visibility_states(UiToggleArgs *args, int *states, int numstates);
 UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
 
+UIEXPORT UiContentToggleArgs* ui_content_toggle_args_new(void);
+UIEXPORT void ui_content_toggle_args_set_fill(UiContentToggleArgs *args, UiBool fill);
+UIEXPORT void ui_content_toggle_args_set_hexpand(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_vexpand(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_hfill(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_vfill(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_override_defaults(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_margin(UiContentToggleArgs *args, int value);
+UIEXPORT void ui_content_toggle_args_set_margin_left(UiContentToggleArgs *args, int value);
+UIEXPORT void ui_content_toggle_args_set_margin_right(UiContentToggleArgs *args, int value);
+UIEXPORT void ui_content_toggle_args_set_margin_top(UiContentToggleArgs *args, int value);
+UIEXPORT void ui_content_toggle_args_set_margin_bottom(UiContentToggleArgs *args, int value);
+UIEXPORT void ui_content_toggle_args_set_colspan(UiContentToggleArgs *args, int colspan);
+UIEXPORT void ui_content_toggle_args_set_rowspan(UiContentToggleArgs *args, int rowspan);
+UIEXPORT void ui_content_toggle_args_set_name(UiContentToggleArgs *args, const char *name);
+UIEXPORT void ui_content_toggle_args_set_style_class(UiContentToggleArgs *args, const char *classname);
+UIEXPORT void ui_content_toggle_args_set_label0(UiContentToggleArgs *args, const char *label);
+UIEXPORT void ui_content_toggle_args_set_icon0(UiContentToggleArgs *args, const char *icon);
+UIEXPORT void ui_content_toggle_args_set_tooltip0(UiContentToggleArgs *args, const char *tooltip);
+UIEXPORT void ui_content_toggle_args_set_label1(UiContentToggleArgs *args, const char *label);
+UIEXPORT void ui_content_toggle_args_set_icon1(UiContentToggleArgs *args, const char *icon);
+UIEXPORT void ui_content_toggle_args_set_tooltip1(UiContentToggleArgs *args, const char *tooltip);
+UIEXPORT void ui_content_toggle_args_set_labeltype(UiContentToggleArgs *args, int labeltype);
+UIEXPORT void ui_content_toggle_args_set_onchange(UiContentToggleArgs *args, ui_callback callback);
+UIEXPORT void ui_content_toggle_args_set_onchangedata(UiContentToggleArgs *args, void *onchangedata);
+UIEXPORT void ui_content_toggle_args_set_action(UiContentToggleArgs *args, const char *action);
+UIEXPORT void ui_content_toggle_args_set_varname(UiContentToggleArgs *args, const char *varname);
+UIEXPORT void ui_content_toggle_args_set_value(UiContentToggleArgs *args, UiInteger *value);
+UIEXPORT void ui_content_toggle_args_set_toggled_by_state(UiContentToggleArgs *args, int state);
+UIEXPORT void ui_content_toggle_args_set_istogglebutton(UiContentToggleArgs *args, UiBool value);
+UIEXPORT void ui_content_toggle_args_set_enablestate(UiContentToggleArgs *args, int state);
+UIEXPORT void ui_content_toggle_args_set_states(UiContentToggleArgs *args, int *states, int numstates);
+UIEXPORT void ui_content_toggle_args_set_visibility_states(UiContentToggleArgs *args, int *states, int numstates);
+UIEXPORT void ui_content_toggle_args_free(UiContentToggleArgs *args);
+
 UIEXPORT UiLinkButtonArgs* ui_linkbutton_args_new(void);
 UIEXPORT void ui_linkbutton_args_set_fill(UiLinkButtonArgs *args, UiBool fill);
 UIEXPORT void ui_linkbutton_args_set_hexpand(UiLinkButtonArgs *args, UiBool value);
@@ -408,6 +467,7 @@ UIEXPORT void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *l
 UIEXPORT void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri);
 UIEXPORT void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback);
 UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata);
+UIEXPORT void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action);
 UIEXPORT void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value);
 UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type);
 UIEXPORT void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates);
@@ -441,14 +501,19 @@ UIEXPORT void ui_list_args_set_getstyle_func(UiListArgs *args, ui_getstylefunc g
 UIEXPORT void ui_list_args_set_getstyle_data(UiListArgs *args, void *userdata);
 UIEXPORT void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback);
 UIEXPORT void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onactivate_action(UiListArgs *args, const char *action);
 UIEXPORT void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback);
 UIEXPORT void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onselection_action(UiListArgs *args, const char *action);
 UIEXPORT void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback);
 UIEXPORT void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragstart_action(UiListArgs *args, const char *action);
 UIEXPORT void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback);
 UIEXPORT void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragcomplete_action(UiListArgs *args, const char *action);
 UIEXPORT void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback);
 UIEXPORT void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondrop_action(UiListArgs *args, const char *action);
 UIEXPORT void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave);
 UIEXPORT void ui_list_args_set_onsavedata(UiListArgs *args, void *userdata);
 UIEXPORT void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection);
@@ -484,6 +549,7 @@ UIEXPORT void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_ca
 UIEXPORT void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata);
 UIEXPORT void ui_sourcelist_args_set_contextmenu(UiSourceListArgs *args, UiMenuBuilder *menubuilder);
 UIEXPORT void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_states(UiSourceListArgs *args, int *states, int numstates);
 UIEXPORT void ui_sourcelist_args_set_visibility_states(UiSourceListArgs *args, int *states, int numstates);
 UIEXPORT void ui_sourcelist_args_free(UiSourceListArgs *args);
 
@@ -505,6 +571,10 @@ UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name);
 UIEXPORT void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname);
 UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback);
 UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
+UIEXPORT void ui_textarea_args_set_onchange_action(UiTextAreaArgs *args, const char *action);
+UIEXPORT void ui_textarea_args_set_ontextchanged(UiTextAreaArgs *args, ui_callback callback);
+UIEXPORT void ui_textarea_args_set_ontextchangeddata(UiTextAreaArgs *args, void *onchangedata);
+UIEXPORT void ui_textarea_args_set_ontextchanged_action(UiTextAreaArgs *args, const char *action);
 UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname);
 UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value);
 UIEXPORT void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates);
@@ -531,6 +601,8 @@ UIEXPORT void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback
 UIEXPORT void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata);
 UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback);
 UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
+UIEXPORT void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action);
+UIEXPORT void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action);
 UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname);
 UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value);
 UIEXPORT void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates);
index 6f0dde99465680b45d09170db06832b5d64836a4..12c62676107e6118043c2d1c11a187204d8e96a1 100644 (file)
@@ -33,13 +33,13 @@ void ui_end_new(UiObject *obj) {
     if(!obj->container_end) {
         return;
     }
-    UiContainerX *rm = obj->container_end;
+    UiContainer *rm = obj->container_end;
     uic_object_pop_container(obj);
     ui_free(obj->ctx, rm);
 }
 
 void ui_newline(UiObject *obj) {
-    UiContainerX *container = obj->container_end;
+    UiContainer *container = obj->container_end;
     if(container) {
         container->newline = TRUE;
     }
index 3e7abfc0cf47e10d78bd2b57065f5f42c3b1f508..757056f491e17100abccadb87920d3b5d0144c65 100644 (file)
@@ -67,13 +67,12 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     ctx->state_widgets = cxLinkedListCreate(mp->allocator, sizeof(UiStateWidget));
     ctx->states = cxArrayListCreate(mp->allocator, sizeof(int), 32);
     cxSetCompareFunc(ctx->states, cx_cmp_int);
+    ctx->suppressed_states = cxArrayListCreate(mp->allocator, sizeof(int), 16);
+    cxSetCompareFunc(ctx->suppressed_states, cx_cmp_int);
     
     ctx->actions = cxHashMapCreate(ctx->allocator, sizeof(UiAction), 8);
     ctx->action_bindings = cxArrayListCreate(ctx->allocator, sizeof(UiActionBinding), 0);
     
-    ctx->attach_document = uic_context_attach_document;
-    ctx->detach_document2 = uic_context_detach_document;
-    
 #if UI_GTK2 || UI_GTK3
     if(toplevel && toplevel->widget) {
         ctx->accel_group = gtk_accel_group_new();
@@ -81,6 +80,8 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     }
 #endif
     
+    ctx->ref = 1;
+    
     return ctx;
 }
 
@@ -95,33 +96,64 @@ void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *d
     cxListAdd(ctx->destroy_handler, &handler);
 }
 
+void uic_context_remove_destructor(UiContext *ctx, void *data) {
+    CxIterator i = cxListIterator(ctx->destroy_handler);
+    cx_foreach(UiDestroyHandler *, handler, i) {
+        if(handler->data == data) {
+            cxIteratorFlagRemoval(i);
+        }
+    }
+}
+
 void uic_context_prepare_close(UiContext *ctx) {
     cxListClear(ctx->states);
     cxListClear(ctx->state_widgets);
+    cxListClear(ctx->action_bindings);
+    uic_context_detach_all(ctx);
 }
 
-void uic_context_attach_document(UiContext *ctx, void *document) {
-    if(ctx->single_document_mode) {
-        if(ctx->document) {
-            uic_context_detach_document(ctx, ctx->document);
-        }
+void uic_context_destroy(UiContext *ctx, void *document) {
+    if(!ctx) {
+        return;
     }
     
-    cxListAdd(ctx->documents, document);
-    ctx->document = document;
+    UiEvent ev;
+    ev.obj = ctx->obj;
+    ev.window = ev.obj ? ev.obj->window : NULL;
+    ev.document = document;
+    ev.eventdata = NULL;
+    ev.eventdatatype = 0;
+    ev.intval = 0;
+    ev.set = 0;
+
+    if(ctx->onclose) {
+        ctx->onclose(&ev, ctx->onclosedata);
+    }
     
-    UiContext *doc_ctx = ui_document_context(document);
-    doc_ctx->parent = ctx;
+    CxIterator i = cxListIterator(ctx->destroy_handler);
+    cx_foreach(UiDestroyHandler *, h, i) {
+        h->destructor(h->data);
+    }
     
+    uic_context_detach_all(ctx);
+
+    cxMempoolFree(ctx->mp);
+}
+
+void uic_context_update_bindings(UiContext *ctx) {
+    int onchange_enabled = ui_onchange_events_is_enabled();
+    int onselection_enabled = ui_selection_events_is_enabled();
+    ui_onchange_events_enable(FALSE);
+    ui_selection_events_enable(FALSE);
     // if a document variable has the same name as a parent variable,
     // move the bindings to the document
-    UiContext *var_ctx = ctx;
+    UiContext *var_ctx = ctx->parent;
     while(var_ctx) {
         CxMapIterator i = cxMapIterator(var_ctx->vars);
         cx_foreach(CxMapEntry*, entry, i) {
-            printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
+            // printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
             UiVar *var = entry->value;
-            UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
+            UiVar *docvar = cxMapGet(ctx->vars, *entry->key);
             if(docvar) {
                 // bind var to document var
                 uic_copy_var_binding(var, docvar, TRUE);
@@ -131,13 +163,59 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
         
         var_ctx = var_ctx->parent;
     }
+      
+    ui_update_action_bindings(ctx);
+    
+    if(ctx->documents) {
+        CxIterator i = cxListIterator(ctx->documents);
+        cx_foreach(void *, doc, i) {
+            UiContext *subctx = ui_document_context(doc);
+            uic_context_update_bindings(subctx);
+        }
+    }
+    ui_onchange_events_enable(onchange_enabled);
+    ui_selection_events_enable(onselection_enabled);
+}
+
+void uic_context_attach_document(UiContext *ctx, void *document) {
+    if(ctx->single_document_mode) {
+        if(ctx->document) {
+            uic_context_detach_document(ctx, ctx->document);
+        }
+    }
+    
+    cxListAdd(ctx->documents, document);
+    ctx->document = document;
+    
+    UiContext *doc_ctx = ui_document_context(document);
+    doc_ctx->parent = ctx;
+    doc_ctx->ref++;
+    
+    uic_context_update_bindings(doc_ctx);
+    if(doc_ctx->onattach) {
+        UiEvent event;
+        memset(&event, 0, sizeof(UiEvent));
+        event.document = document;
+        doc_ctx->onattach(&event, doc_ctx->onattachdata);
+    }
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+    UiObject *obj = ui_context_get_parent_obj(ctx);
+    uic_send_status_change(doc_ctx, obj);
+    
+    UiContext *obj_ctx = uic_obj_context(ctx);
+    if(obj_ctx) {
+        ui_update_action_bindings(obj_ctx);
+    }
 }
 
 static void uic_context_unbind_vars(UiContext *ctx) {
+    int onchange_enabled = ui_onchange_events_is_enabled();
+    int onselection_enabled = ui_selection_events_is_enabled();
     ui_onchange_events_enable(FALSE);
+    ui_selection_events_enable(FALSE);
     CxMapIterator mi = cxMapIterator(ctx->vars);
     cx_foreach(CxMapEntry*, entry, mi) {
-        printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
+        //printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
         UiVar *var = entry->value;
         // var->from && var->from_ctx && var->from_ctx != ctx
         uic_save_var(var);
@@ -157,7 +235,8 @@ static void uic_context_unbind_vars(UiContext *ctx) {
         }
     }
     
-    ui_onchange_events_enable(TRUE);
+    ui_onchange_events_enable(onchange_enabled);
+    ui_selection_events_enable(onselection_enabled);
 }
 
 void uic_context_detach_document(UiContext *ctx, void *document) {
@@ -170,9 +249,24 @@ void uic_context_detach_document(UiContext *ctx, void *document) {
     cxListRemove(ctx->documents, docIndex);
     ctx->document = cxListAt(ctx->documents, 0);
     
-    UiContext *docctx = ui_document_context(document);
-    uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent
-    docctx->parent = NULL;
+    UiContext *doc_ctx = ui_document_context(document);
+    uic_context_unbind_vars(doc_ctx); // unbind all doc/subdoc vars from the parent
+    doc_ctx->parent = NULL;
+    
+    UiContext *obj_ctx = uic_obj_context(ctx);
+    if(obj_ctx) {
+        ui_update_action_bindings(obj_ctx);
+    }
+    if(doc_ctx->ondetach) {
+        UiEvent event;
+        memset(&event, 0, sizeof(UiEvent));
+        event.document = document;
+        doc_ctx->ondetach(&event, doc_ctx->ondetachdata);
+    }
+    
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+    uic_send_status_change(doc_ctx, NULL);
+    ui_document_unref(document);
 }
 
 void uic_context_detach_all(UiContext *ctx) {
@@ -186,12 +280,40 @@ void uic_context_detach_all(UiContext *ctx) {
     // detach documents
     i = cxListIterator(ls);
     cx_foreach(void *, doc, i) {
-        ctx->detach_document2(ctx, doc);
+        uic_context_detach_document(ctx, doc);
     }
     
     cxListFree(ls);
+    ui_update_action_bindings(ctx);
+}
+
+static void send_status_change(UiContext *ctx, UiEvent *event, UiObject *obj) {
+    CxIterator i = cxListIterator(ctx->documents);
+    cx_foreach(void *, doc, i) {
+        UiContext *doc_ctx = ui_document_context(doc);
+        if(doc_ctx->onattachmentstatuschange) {
+            event->obj = doc_ctx->obj ? doc_ctx->obj : obj;
+            event->window = event->obj ? event->obj->window : NULL;
+            event->document = doc_ctx->self_doc ? doc_ctx->self_doc : doc_ctx->document;
+            doc_ctx->onattachmentstatuschange(event, doc_ctx->onattachmentstatuschangedata);
+        }
+    }
+    
+    if(ctx->onattachmentstatuschange) {
+        event->obj = ctx->obj ? ctx->obj : obj;
+        event->window = event->obj ? event->obj->window : NULL;
+        event->document = ctx->self_doc ? ctx->self_doc : ctx->document;
+        ctx->onattachmentstatuschange(event, ctx->onattachmentstatuschangedata);
+    }
+}
+
+void uic_send_status_change(UiContext *ctx, UiObject *obj) {
+    UiEvent event;
+    memset(&event, 0, sizeof(UiEvent));
+    send_status_change(ctx, &event, obj);
 }
 
+
 static UiVar* ctx_getvar(UiContext *ctx, CxHashKey key) {
     UiVar *var = cxMapGet(ctx->vars, key);
     if(!var && ctx->documents) {
@@ -407,8 +529,21 @@ void uic_copy_value_binding(UiVarType type, void *from, void *to) {
         case UI_VAR_LIST: {         
             UiList *f = from;
             UiList *t = to;
+            // save selection
+            ui_list_selection_free(f->saved_selection);
+            if(f->getselection && f->save_selection) {
+                f->saved_selection = ui_list_get_selection_allocated(f);
+            } else {
+                f->saved_selection = NULL;
+            }
+    
             uic_list_copy(f, t);
             ui_list_update(t);
+            if(t->setselection && t->saved_selection) {
+                t->setselection(t, *t->saved_selection);
+            }
+            ui_list_selection_free(t->saved_selection);
+            t->saved_selection = NULL;
             break;
         }
         case UI_VAR_RANGE: {
@@ -520,22 +655,23 @@ void ui_detach_document(UiContext *ctx, void *document) {
 }
 
 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
-    ctx->close_callback = fnc;
-    ctx->close_data = udata;
-}
-
-void ui_context_destroy(UiContext *ctx) {
-    CxIterator i = cxListIterator(ctx->destroy_handler);
-    cx_foreach(UiDestroyHandler *, h, i) {
-        h->destructor(h->data);
-    }
-    cxMempoolFree(ctx->mp);
+    ctx->onclose = fnc;
+    ctx->onclosedata = udata;
 }
 
 UiContext* ui_context_parent(UiContext *ctx) {
     return ctx->parent;
 }
 
+UiContext* ui_context_toplevel_parent(UiContext *ctx) {
+    if(ctx->obj) {
+        return ctx;
+    } else if (ctx->parent) {
+        return ui_context_toplevel_parent(ctx->parent);
+    }
+    return NULL;
+}
+
 
 void ui_set_state(UiContext *ctx, int state) {
     if(!cxListIndexValid(ctx->states, cxListFind(ctx->states, &state))) {
@@ -543,7 +679,7 @@ void ui_set_state(UiContext *ctx, int state) {
     }
     
     // enable/disable group widgets
-    uic_check_state_widgets(ctx);
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
 }
 
 void ui_unset_state(UiContext *ctx, int state) {
@@ -553,25 +689,94 @@ void ui_unset_state(UiContext *ctx, int state) {
     }
     
     // enable/disable group widgets
-    uic_check_state_widgets(ctx);
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
+void ui_suppress_state(UiContext *ctx, int state) {
+    if(!cxListIndexValid(ctx->suppressed_states, cxListFind(ctx->suppressed_states, &state))) {
+        cxListAdd(ctx->suppressed_states, &state);
+    }
+    
+    // enable/disable group widgets
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
+void ui_unsuppress_state(UiContext *ctx, int state) {
+    int i = cxListFind(ctx->suppressed_states, &state);
+    if(i != -1) {
+        cxListRemove(ctx->suppressed_states, i);
+    }
+    
+    // enable/disable group widgets
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
+typedef struct StatesList {
+    CX_ARRAY(int, states);
+    CX_ARRAY(int, suppressed);
+} StatesList;
+
+static void add_ctx_states(UiContext *ctx, StatesList *states) {
+    size_t nstates = cxListSize(ctx->states);
+    int *ctx_states = cxListAt(ctx->states, 0);
+    
+    size_t nsuppressed = cxListSize(ctx->suppressed_states);
+    int *ctx_suppressed_states = cxListAt(ctx->suppressed_states, 0);
+    
+    cx_array_add_array(states->states, ctx_states, nstates);
+    cx_array_add_array(states->suppressed, ctx_suppressed_states, nsuppressed);
+    
+    CxIterator i = cxListIterator(ctx->documents);
+    cx_foreach(void *, doc, i) {
+        UiContext *doc_ctx = ui_document_context(doc);
+        add_ctx_states(doc_ctx, states);
+    }
 }
 
 int* ui_active_states(UiContext *ctx, int *nstates) {
-    *nstates = cxListSize(ctx->states);
-    return cxListAt(ctx->states, 0);
+    StatesList states;
+    cx_array_init(states.states, 32);
+    cx_array_init(states.suppressed, 8);
+    add_ctx_states(ctx, &states);
+    
+    // remove suppressed states
+    for(size_t i=0;i<states.suppressed.size;i++) {
+        int suppressed = states.suppressed.data[i];
+        // important to use ssize_t for the index here
+        for(ssize_t s=0;s<states.states.size;s++) {
+            if(states.states.data[s] == suppressed) {
+                // this state is suppressed
+                if(s+1 < states.states.size) {
+                    // copy last element to the current position
+                    states.states.data[s] = states.states.data[states.states.size-1];
+                    // we need to check the current index again
+                    s--;
+                }
+                states.states.size--;
+            }
+        }
+    }
+    
+    free(states.suppressed.data);
+    *nstates = (int)states.states.size;
+    return states.states.data;
 }
 
 void uic_check_state_widgets(UiContext *ctx) {
-    int ngroups = 0;
-    int *groups = ui_active_states(ctx, &ngroups);
+    if(!ctx) {
+        return;
+    }
+    
+    int nstates = 0;
+    int *states = ui_active_states(ctx, &nstates);
     
     CxIterator i = cxListIterator(ctx->state_widgets);
     cx_foreach(UiStateWidget *, gw, i) {
         char *check = calloc(1, gw->numstates);
         
-        for(int i=0;i<ngroups;i++) {
+        for(int i=0;i<nstates;i++) {
             for(int k=0;k<gw->numstates;k++) {
-                if(groups[i] == gw->states[k]) {
+                if(states[i] == gw->states[k]) {
                     check[k] = 1;
                 }
             }
@@ -587,6 +792,8 @@ void uic_check_state_widgets(UiContext *ctx) {
         free(check);
         gw->enable(gw->widget, enable);
     }
+    
+    free(states);
 }
 
 void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
@@ -671,26 +878,30 @@ void* ui_cx_mempool(UiContext *ctx) {
 }
 
 void* ui_malloc(UiContext *ctx, size_t size) {
-    return ctx ? cxMalloc(ctx->allocator, size) : NULL;
+    return ctx ? cxMalloc(ctx->allocator, size) : malloc(size);
 }
 
 void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize) {
-    return ctx ? cxCalloc(ctx->allocator, nelem, elsize) : NULL;
+    return ctx ? cxCalloc(ctx->allocator, nelem, elsize) : calloc(nelem, elsize);
 }
 
 void ui_free(UiContext *ctx, void *ptr) {
-    if(ctx && ptr) {
-        cxFree(ctx->allocator, ptr);
+    if(ptr) {
+        if(ctx) {
+            cxFree(ctx->allocator, ptr);
+        } else {
+            free(ptr);
+        }
     }
 }
 
 void* ui_realloc(UiContext *ctx, void *ptr, size_t size) {
-    return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL;
+    return ctx ? cxRealloc(ctx->allocator, ptr, size) : realloc(ptr, size);
 }
 
 char* ui_strdup(UiContext *ctx, const char *str) {
     if(!ctx) {
-        return NULL;
+        return strdup(str ? str : "");
     }
     cxstring s = cx_str(str);
     cxmutstr d = cx_strdup_a(ctx->allocator, s);
@@ -698,7 +909,12 @@ char* ui_strdup(UiContext *ctx, const char *str) {
 }
 
 void  ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) {
-    cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr);
+    //cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr);
+    uic_context_add_destructor(ctx, destr, data);
+}
+
+void  ui_remove_destructor(UiContext *ctx, void *data) {
+    uic_context_remove_destructor(ctx, data);
 }
 
 void  ui_set_destructor(void *mem, ui_destructor_func destr) {
@@ -850,3 +1066,66 @@ UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name) {
     UiVar *var = uic_get_var_t(ctx, name, UI_VAR_GENERIC);
     return var ? var->value : NULL;
 }
+
+
+
+void ui_context_onattach(UiContext *ctx, ui_callback cb, void *data) {
+    ctx->onattach = cb;
+    ctx->onattachdata = data;
+}
+
+void ui_context_ondetach(UiContext *ctx, ui_callback cb, void *data) {
+    ctx->ondetach = cb;
+    ctx->ondetachdata = data;
+}
+
+void ui_context_onattachmentstatuschange(UiContext *ctx, ui_callback cb, void *data) {
+    ctx->onattachmentstatuschange = cb;
+    ctx->onattachmentstatuschangedata = data;
+}
+
+static void attachment_action_callback(UiEvent *event, void *action) {
+    if(event->document) {
+        UiContext *ctx = ui_document_context(event->document);
+        ui_call_action_on(ctx, action);
+    }
+}
+
+void ui_context_onattach_action(UiContext *ctx, const char *action) {
+    ctx->onattach = attachment_action_callback;
+    ctx->onattachdata = ui_strdup(ctx, action);
+}
+
+void ui_context_ondetach_action(UiContext *ctx, const char *action) {
+    ctx->ondetach = attachment_action_callback;
+    ctx->ondetachdata = ui_strdup(ctx, action);
+}
+
+void ui_context_onattachmentstatuschange_action(UiContext *ctx, const char *action) {
+    ctx->onattachmentstatuschange = attachment_action_callback;
+    ctx->onattachmentstatuschangedata = ui_strdup(ctx, action);
+}
+
+
+int ui_context_is_attached(UiContext *ctx) {
+    return ctx->parent != NULL;
+}
+
+int ui_context_is_attached_to_obj(UiContext *ctx) {
+    return uic_obj_context(ctx) != NULL;
+}
+
+UIEXPORT UiObject* ui_context_get_parent_obj(UiContext *ctx) {
+    UiContext *obj_ctx = uic_obj_context(ctx);
+    return obj_ctx ? obj_ctx->obj : NULL;
+}
+
+UiContext* uic_obj_context(UiContext *ctx) {
+    if(ctx->obj) {
+        return ctx;
+    }
+    if(ctx->parent == NULL) {
+        return NULL;
+    }
+    return uic_obj_context(ctx->parent);
+}
index de804818de35418ee6118d0172d5bdceafe05cfa..071800749f55dd11ba5f4809dd4aa61531a6c3ad 100644 (file)
@@ -62,24 +62,25 @@ typedef enum UiVarType {
 struct UiContext {
     UiContext     *parent;
     UiObject      *obj;
-    CxMempool *mp;
+    CxMempool     *mp;
     const CxAllocator *allocator;
     CxList *destroy_handler;
     
+    // document pointer, if this is a document context
+    void          *self_doc;
+    
     void          *document;
     CxList        *documents;
     
     CxMap         *vars;
     
     CxList        *states; // int list
+    CxList        *suppressed_states; // int list
     CxList        *state_widgets; // UiGroupWidget list
     
     CxMap         *actions; // key: action name (string), value: UiAction
     CxList        *action_bindings; // UiActionBinding list
     
-    void (*attach_document)(UiContext *ctx, void *document);
-    void (*detach_document2)(UiContext *ctx, void *document); 
-    
     char          *title;
     
 #ifdef UI_GTK
@@ -98,8 +99,19 @@ struct UiContext {
     // attaching a document will automatically detach the current document
     UiBool single_document_mode;
     
-    ui_callback   close_callback;
-    void          *close_data;
+    ui_callback   onattach;
+    void          *onattachdata;
+    
+    ui_callback   ondetach;
+    void          *ondetachdata;
+    
+    ui_callback   onattachmentstatuschange;
+    void          *onattachmentstatuschangedata;
+    
+    ui_callback   onclose;
+    void          *onclosedata;
+    
+    unsigned int  ref;
 };
 
 struct UiVar {
@@ -129,15 +141,20 @@ void uic_init_global_context(void);
 UiContext* uic_context(UiObject *toplevel, CxMempool *mp);
 UiContext* uic_root_context(UiContext *ctx);
 void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
+void uic_context_remove_destructor(UiContext *ctx, void *data);
 
 void uic_context_prepare_close(UiContext *ctx);
+void uic_context_destroy(UiContext *ctx, void *document);
 
+void uic_context_update_bindings(UiContext *ctx);
 void uic_context_attach_document(UiContext *ctx, void *document);
 void uic_context_detach_document(UiContext *ctx, void *document);
 void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
 void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
 void uic_context_detach_all(UiContext *ctx);
 
+void uic_send_status_change(UiContext *ctx, UiObject *obj);
+
 UiVar* uic_get_var(UiContext *ctx, const char *name);
 UiVar* uic_get_var_t(UiContext *ctx, const char *name, UiVarType type);
 UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type);
@@ -162,6 +179,19 @@ void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, Cx
 void uic_add_state_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *states, size_t numstates);
 void uic_remove_state_widget(UiContext *ctx, void *widget);
 
+UiContext* uic_obj_context(UiContext *ctx);
+
+UIEXPORT void ui_context_onattach(UiContext *ctx, ui_callback cb, void *data);
+UIEXPORT void ui_context_ondetach(UiContext *ctx, ui_callback cb, void *data);
+UIEXPORT void ui_context_onattachmentstatuschange(UiContext *ctx, ui_callback cb, void *data);
+UIEXPORT void ui_context_onattach_action(UiContext *ctx, const char *action);
+UIEXPORT void ui_context_ondetach_action(UiContext *ctx, const char *action);
+UIEXPORT void ui_context_onattachmentstatuschange_action(UiContext *ctx, const char *action);
+
+UIEXPORT int ui_context_is_attached(UiContext *ctx);
+UIEXPORT int ui_context_is_attached_to_obj(UiContext *ctx);
+UIEXPORT UiObject* ui_context_get_parent_obj(UiContext *ctx);
+
 #ifdef __cplusplus
 }
 #endif
index 3eb5874d870d9989fd28d3b6fbbb0f5ce45ac2c3..287b5b51f81d7dd1001b5c0aba93a492b540f7eb 100644 (file)
@@ -45,24 +45,27 @@ void* ui_document_new(size_t size) {
     
     UiDoc *document = cxCalloc(a, sizeof(UiDoc) + size, 1);
     document->ctx = ctx;
-    return &document->doc;
+    ctx->self_doc = &document->doc;
+    return ctx->self_doc;
 }
 
 void ui_document_destroy(void *doc) {
+    uic_context_destroy(ui_document_context(doc), doc);
+}
+
+void ui_document_ref(void *doc) {
     UiContext *ctx = ui_document_context(doc);
     if(ctx) {
-        UiEvent ev;
-        ev.window = NULL;
-        ev.document = doc;
-        ev.obj = NULL;
-        ev.eventdata = NULL;
-        ev.eventdatatype = 0;
-        ev.intval = 0;
-
-        if(ctx->close_callback) {
-            ctx->close_callback(&ev, ctx->close_data);
+        ctx->ref++;
+    }
+}
+
+void ui_document_unref(void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(ctx) {
+        if(--ctx->ref == 0) {
+            uic_context_destroy(ctx, doc);
         }
-        cxMempoolFree(ctx->mp);
     }
 }
 
@@ -75,3 +78,52 @@ UiContext* ui_document_context(void *doc) {
         return NULL;
     }
 }
+
+void* ui_context_document(UiContext *ctx) {
+    return ctx->self_doc;
+}
+
+UiObject* ui_context_obj(UiContext *ctx) {
+    return ctx->obj;
+}
+
+void ui_document_onattach(void *doc, ui_callback cb, void *data) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_onattach(ctx, cb, data);
+}
+
+void ui_document_ondetach(void *doc, ui_callback cb, void *data) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_ondetach(ctx, cb, data);
+}
+
+void  ui_document_onattachmentstatuschange(void *doc, ui_callback cb, void *data) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_onattachmentstatuschange(ctx, cb, data);
+}
+
+void ui_document_onattach_action(void *doc, const char *action) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_onattach_action(ctx, action);
+}
+
+void ui_document_ondetach_action(void *doc, const char *action) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_ondetach_action(ctx, action);
+}
+
+void  ui_document_onattachmentstatuschange_action(void *doc, const char *action) {
+    UiContext *ctx = ui_document_context(doc);
+    ui_context_onattachmentstatuschange_action(ctx, action);
+}
+
+
+int ui_document_is_attached(void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    return ui_context_is_attached(ctx);
+}
+
+int ui_document_is_attached_to_obj(void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    return ui_context_is_attached_to_obj(ctx);
+}
diff --git a/ui/common/icons.c b/ui/common/icons.c
new file mode 100644 (file)
index 0000000..377b1a7
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "icons.h"
+
+const char* ui_icon_name(enum UiIconId icon_id) {
+    switch(icon_id) {
+        case UI_ICON_ID_HOME                 : return UI_ICON_HOME;
+        case UI_ICON_ID_NEW_WINDOW           : return UI_ICON_NEW_WINDOW;
+        case UI_ICON_ID_NEW_TAB              : return UI_ICON_NEW_TAB;
+        case UI_ICON_ID_NEW_FOLDER           : return UI_ICON_NEW_FOLDER;
+        case UI_ICON_ID_NEW_DOCUMENT         : return UI_ICON_NEW_DOCUMENT;
+        case UI_ICON_ID_NEW_APPOINTMENT      : return UI_ICON_NEW_APPOINTMENT;
+        case UI_ICON_ID_NEW_CHAT_MESSAGE     : return UI_ICON_NEW_CHAT_MESSAGE;
+        case UI_ICON_ID_NEW_CONTACT          : return UI_ICON_NEW_CONTACT;
+        case UI_ICON_ID_NEW_MAIL             : return UI_ICON_NEW_MAIL;
+        case UI_ICON_ID_ADD_BOOKMARK         : return UI_ICON_ADD_BOOKMARK;
+        case UI_ICON_ID_ADD_IMAGE            : return UI_ICON_ADD_IMAGE;
+        case UI_ICON_ID_ADD_LINK             : return UI_ICON_ADD_LINK;
+        case UI_ICON_ID_ADD_TEXT             : return UI_ICON_ADD_TEXT;
+        case UI_ICON_ID_ADD                  : return UI_ICON_ADD;
+        case UI_ICON_ID_REMOVE               : return UI_ICON_REMOVE;
+        case UI_ICON_ID_REFRESH              : return UI_ICON_REFRESH;
+        case UI_ICON_ID_UPLOAD               : return UI_ICON_UPLOAD;
+        case UI_ICON_ID_SAVE_LOCAL           : return UI_ICON_SAVE_LOCAL;
+        case UI_ICON_ID_EDIT_COPY            : return UI_ICON_EDIT_COPY;
+        case UI_ICON_ID_EDIT_CUT             : return UI_ICON_EDIT_CUT;
+        case UI_ICON_ID_EDIT_DELETE          : return UI_ICON_EDIT_DELETE;
+        case UI_ICON_ID_EDIT_PASTE           : return UI_ICON_EDIT_PASTE ;
+        case UI_ICON_ID_UNDO                 : return UI_ICON_UNDO;
+        case UI_ICON_ID_REDO                 : return UI_ICON_REDO;
+        case UI_ICON_ID_SIDEBAR_LEFT         : return UI_ICON_SIDEBAR_LEFT;
+        case UI_ICON_ID_SIDEBAR_RIGHT        : return UI_ICON_SIDEBAR_RIGHT;
+        case UI_ICON_ID_GO_BACK              : return UI_ICON_GO_BACK;
+        case UI_ICON_ID_GO_FORWARD           : return UI_ICON_GO_FORWARD ;
+        case UI_ICON_ID_GO_UP                : return UI_ICON_GO_UP;
+        case UI_ICON_ID_GO_DOWN              : return UI_ICON_GO_DOWN;
+        case UI_ICON_ID_VIEW_LIST            : return UI_ICON_VIEW_LIST;
+        case UI_ICON_ID_VIEW_GRID            : return UI_ICON_VIEW_GRID;
+        case UI_ICON_ID_VIEW_DUAL            : return UI_ICON_VIEW_DUAL;
+        case UI_ICON_ID_VIEW_FULLSCREEN      : return UI_ICON_VIEW_FULLSCREEN;
+        case UI_ICON_ID_VIEW_RESTORE         : return UI_ICON_VIEW_RESTORE;
+        case UI_ICON_ID_TEXT_BOLD            : return UI_ICON_TEXT_BOLD;
+        case UI_ICON_ID_TEXT_ITALIC          : return UI_ICON_TEXT_ITALIC;
+        case UI_ICON_ID_TEXT_UNDERLINE       : return UI_ICON_TEXT_UNDERLINE;
+        case UI_ICON_ID_LIST_BULLET          : return UI_ICON_LIST_BULLET ;
+        case UI_ICON_ID_LIST_ORDERED         : return UI_ICON_LIST_ORDERED;
+        case UI_ICON_ID_LIST_CHECK           : return UI_ICON_LIST_CHECK;
+        case UI_ICON_ID_CHECKBOX             : return UI_ICON_CHECKBOX;
+        case UI_ICON_ID_STAR                 : return UI_ICON_STAR;
+        case UI_ICON_ID_VIEW_REVEAL          : return UI_ICON_VIEW_REVEAL;
+        case UI_ICON_ID_VIEW_CONCEAL         : return UI_ICON_VIEW_CONCEAL;
+        case UI_ICON_ID_SETTINGS             : return UI_ICON_SETTINGS;
+        case UI_ICON_ID_MEDIA_PLAY           : return UI_ICON_MEDIA_PLAY;
+        case UI_ICON_ID_MEDIA_STOP           : return UI_ICON_MEDIA_STOP;
+        case UI_ICON_ID_MEDIA_PAUSE          : return UI_ICON_MEDIA_PAUSE;
+        case UI_ICON_ID_MEDIA_SEEK_BACKWARD  : return UI_ICON_MEDIA_SEEK_BACKWARD;
+        case UI_ICON_ID_MEDIA_SEEK_FORWARD   : return UI_ICON_MEDIA_SEEK_FORWARD;
+        case UI_ICON_ID_MEDIA_SKIP_BACKWARD  : return UI_ICON_MEDIA_SKIP_BACKWARD;
+        case UI_ICON_ID_MEDIA_SKIP_FORWARD   : return UI_ICON_MEDIA_SKIP_FORWARD;
+        case UI_ICON_ID_CALL_START           : return UI_ICON_CALL_START;
+        case UI_ICON_ID_CALL_STOP            : return UI_ICON_CALL_STOP;
+        case UI_ICON_ID_CALL_INCOMING        : return UI_ICON_CALL_INCOMING;
+        case UI_ICON_ID_CALL_OUTGOING        : return UI_ICON_CALL_OUTGOING;
+        case UI_ICON_ID_MICROPHONE_ON        : return UI_ICON_MICROPHONE_ON;
+        case UI_ICON_ID_MICROPHONE_OFF       : return UI_ICON_MICROPHONE_OFF;
+        case UI_ICON_ID_LOCKED               : return UI_ICON_LOCKED;
+        case UI_ICON_ID_UNLOCKED             : return UI_ICON_UNLOCKED;
+        case UI_ICON_ID_SECURE               : return UI_ICON_SECURE;
+        case UI_ICON_ID_INSECURE             : return UI_ICON_INSECURE;    
+    }
+    return NULL;
+}
diff --git a/ui/common/icons.h b/ui/common/icons.h
new file mode 100644 (file)
index 0000000..d7062a6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_ICONS_H
+#define UIC_ICONS_H
+
+#include "../ui/icons.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_ICONS_H */
+
index b0a5d2e6bad0e69bdf40c2e182563cf6e54feeaa..83eb2589e238701b32fbcdf5d1e2ac53e0ecbf6a 100644 (file)
@@ -44,6 +44,17 @@ static int menu_item_counter = 0;
 static void *tmp_eventdata;
 static int tmp_eventdata_type;
 
+
+static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+    ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
+    return getvalue(elm, col);
+}
+
+static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+    return elm;
+}
+
+
 void uic_set_tmp_eventdata(void *eventdata, int type) {
     tmp_eventdata = eventdata;
     tmp_eventdata_type = type;
@@ -148,6 +159,7 @@ void ui_menuitem_create(UiMenuItemArgs *args) {
     item->item.next = NULL;
     item->item.type = UI_MENU_ITEM;
 
+    item->action = nl_strdup(args->action);
     item->label = nl_strdup(args->label);
     item->icon = nl_strdup(args->icon);
     item->userdata = args->onclickdata;
@@ -207,7 +219,15 @@ void ui_menu_itemlist_create(UiMenuItemListArgs *args) {
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_ITEM_LIST;
-    item->getvalue = args->getvalue;
+    if(args->getvalue2) {
+        item->getvalue = args->getvalue2;
+        item->getvaluedata = args->getvaluedata;
+    } else if(args->getvalue) {
+        item->getvalue = getvalue_wrapper;
+        item->getvaluedata = (void*)args->getvalue;
+    } else {
+        item->getvalue = str_getvalue;
+    }
     item->callback = args->onselect;
     item->userdata = args->onselectdata;
     item->varname = nl_strdup(args->varname);
@@ -222,6 +242,15 @@ void ui_menu_checkitemlist_create(UiMenuItemListArgs *args) {
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_CHECKITEM_LIST;
+    if(args->getvalue2) {
+        item->getvalue = args->getvalue2;
+        item->getvaluedata = args->getvaluedata;
+    } else if(args->getvalue) {
+        item->getvalue = getvalue_wrapper;
+        item->getvaluedata = (void*)args->getvalue;
+    } else {
+        item->getvalue = str_getvalue;
+    }
     item->callback = args->onselect;
     item->userdata = args->onselectdata;
     item->varname = nl_strdup(args->varname);
@@ -235,6 +264,15 @@ void ui_menu_radioitemlist_create(UiMenuItemListArgs *args) {
     item->item.prev = NULL;
     item->item.next = NULL;
     item->item.type = UI_MENU_RADIOITEM_LIST;
+    if(args->getvalue2) {
+        item->getvalue = args->getvalue2;
+        item->getvaluedata = args->getvaluedata;
+    } else if(args->getvalue) {
+        item->getvalue = getvalue_wrapper;
+        item->getvaluedata = (void*)args->getvalue;
+    } else {
+        item->getvalue = str_getvalue;
+    }
     item->callback = args->onselect;
     item->userdata = args->onselectdata;
     item->varname = nl_strdup(args->varname);
index 9aea5789962c531fddfc7e618f7307197a1c275f..510e504f100f1fa0a6a5466fbc7e67aede2848d4 100644 (file)
@@ -76,6 +76,7 @@ struct UiMenu {
 struct UiMenuItem {
     UiMenuItemI    item;
     ui_callback    callback;
+    char           *action;
     char           *label;
     char           *icon;
     void           *userdata;
@@ -106,12 +107,13 @@ struct UiMenuRadioItem {
 };
 
 struct UiMenuItemList {
-    UiMenuItemI     item;
-    ui_getvaluefunc getvalue;
-    ui_callback     callback;
-    void            *userdata;
-    char            *varname;
-    UiBool          addseparator;
+    UiMenuItemI      item;
+    ui_getvaluefunc2 getvalue;
+    void             *getvaluedata;
+    ui_callback      callback;
+    void             *userdata;
+    char             *varname;
+    UiBool           addseparator;
 };
 
 
index 9b197d7edb235905c4579f07721859bed49c8dfc..8ea5b37e6438154a3ecdf73f2b1cabeb283e650b 100644 (file)
@@ -39,6 +39,8 @@
 static CxList *creation_callbacks;
 static CxList *destruction_callbacks;
 
+static CxList *objects;
+
 typedef struct objcallback {
     ui_object_callback func;
     void *userdata;
@@ -67,6 +69,11 @@ UiObject* ui_dummy_object(void) {
 }
 
 void uic_object_created(UiObject *obj) {
+    if(!objects) {
+        objects = cxLinkedListCreate(NULL, CX_STORE_POINTERS);
+    }
+    cxListAdd(objects, obj);
+    
     CxIterator i = cxListIterator(creation_callbacks);
     cx_foreach(objcallback *, cb, i) {
         cb->func(obj, cb->userdata);
@@ -74,12 +81,20 @@ void uic_object_created(UiObject *obj) {
 }
 
 void uic_object_destroyed(UiObject *obj) {
+    if(objects) {
+        cxListFindRemove(objects, obj);
+    }
+    
     CxIterator i = cxListIterator(destruction_callbacks);
     cx_foreach(objcallback *, cb, i) {
         cb->func(obj, cb->userdata);
     }
 }
 
+CxList* uic_object_list(void) {
+    return objects ? objects : cxEmptyList;
+}
+
 void ui_object_ref(UiObject *obj) {
     obj->ref++;
 }
@@ -88,28 +103,20 @@ int ui_object_unref(UiObject *obj) {
     // it is possible to have 0 references, in case
     // a window was created but ui_show was never called
     if(obj->ref == 0 || --obj->ref == 0) {
+        uic_context_prepare_close(obj->ctx);
         if(obj->destroy) {
             obj->destroy(obj);
+        } else {
+            uic_object_destroy(obj);
         }
-        uic_object_destroy(obj);
         return 0;
     }
     return 1;
 }
 
 void uic_object_destroy(UiObject *obj) {
-    if(obj->ctx->close_callback) {
-        UiEvent ev;
-        ev.window = obj->window;
-        ev.document = obj->ctx->document;
-        ev.obj = obj;
-        ev.eventdata = NULL;
-        ev.eventdatatype = 0;
-        ev.intval = 0;
-        obj->ctx->close_callback(&ev, obj->ctx->close_data);
-    }
     uic_object_destroyed(obj);
-    cxMempoolFree(obj->ctx->mp);
+    uic_context_destroy(obj->ctx, obj->ctx->document);
 }
 
 UiObject* uic_object_new_toplevel(void) {
@@ -129,7 +136,7 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
     return newobj;
 }
 
-void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer) {
+void uic_object_push_container(UiObject *toplevel, UiContainer *newcontainer) {
     newcontainer->prev = toplevel->container_end;
     if(toplevel->container_end) {
         toplevel->container_end->next = newcontainer;
@@ -158,8 +165,8 @@ void uic_object_pop_container(UiObject *toplevel) {
  */
 void uic_object_remove_second_last_container(UiObject *toplevel) {
     if(toplevel->container_end && toplevel->container_end->prev) {
-        UiContainerX *end = toplevel->container_end;
-        UiContainerX *rm = toplevel->container_end->prev;
+        UiContainer *end = toplevel->container_end;
+        UiContainer *rm = toplevel->container_end->prev;
         
         end->prev = rm->prev;
         if(rm->prev) {
index 43278752ef904f4cef2741721d3b639f66ff6832..7ef1e1232af0269b722d7a7c5249cf38bfe88c26 100644 (file)
@@ -50,12 +50,14 @@ void uic_object_created(UiObject *obj);
 void uic_object_destroyed(UiObject *obj);
     
 void uic_object_destroy(UiObject *obj);
+
+CxList* uic_object_list(void);
     
 UiObject* uic_object_new_toplevel(void);
 UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget);
 UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
 
-void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer);
+void uic_object_push_container(UiObject *toplevel, UiContainer *newcontainer);
 void uic_object_pop_container(UiObject *toplevel);
 void uic_object_remove_second_last_container(UiObject *toplevel);
 
index 2ce73a5d7e14c3b2e7e5abc78d358fa80db7010e..35fb9d6d28255f2706c28bf13fbc1c2b1ae86014 100644 (file)
@@ -45,6 +45,7 @@ COMMON_OBJ += args$(OBJ_EXT)
 COMMON_OBJ += wrapper$(OBJ_EXT)
 COMMON_OBJ += utils$(OBJ_EXT)
 COMMON_OBJ += message$(OBJ_EXT)
+COMMON_OBJ += icons$(OBJ_EXT)
 
 TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
 TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
index f87e02a373a8fd97ca16e63ef1b9b3ddf98a47ee..552b8e12dc26d279c94a77bbe555094ebe8182ca 100644 (file)
@@ -57,6 +57,7 @@ static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups,
     newargs.tooltip = nl_strdup(args->tooltip);\r
     newargs.onclick = args->onclick;\r
     newargs.onclickdata = args->onclickdata;\r
+    newargs.action = nl_strdup(args->action);\r
     newargs.states = uic_copy_states(args->states, ngroups);\r
     newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
     return newargs;\r
@@ -78,6 +79,26 @@ static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args
     newargs.varname = nl_strdup(args->varname);\r
     newargs.onchange = args->onchange;\r
     newargs.onchangedata = args->onchangedata;\r
+    newargs.action = nl_strdup(args->action);\r
+    newargs.states = uic_copy_states(args->states, ngroups);\r
+    newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
+    return newargs;\r
+}\r
+\r
+static UiToolbarContentToggleItemArgs contenttoggleitemargs_copy(UiToolbarContentToggleItemArgs *args, size_t *ngroups, size_t *nvstates) {\r
+    UiToolbarContentToggleItemArgs newargs;\r
+    newargs.label0 = nl_strdup(args->label0);\r
+    newargs.icon0 = nl_strdup(args->icon0);\r
+    newargs.tooltip0 = nl_strdup(args->tooltip0);\r
+    newargs.label1 = nl_strdup(args->label1);\r
+    newargs.icon1 = nl_strdup(args->icon1);\r
+    newargs.tooltip1 = nl_strdup(args->tooltip1);\r
+    newargs.varname = nl_strdup(args->varname);\r
+    newargs.onchange = args->onchange;\r
+    newargs.onchangedata = args->onchangedata;\r
+    newargs.action = nl_strdup(args->action);\r
+    newargs.toggled_by_state = args->toggled_by_state;\r
+    newargs.istogglebutton = args->istogglebutton;\r
     newargs.states = uic_copy_states(args->states, ngroups);\r
     newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
     return newargs;\r
@@ -90,6 +111,13 @@ void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *arg
     cxMapPut(toolbar_items, name, item);\r
 }\r
 \r
+void ui_toolbar_content_toggleitem_create(const char* name, UiToolbarContentToggleItemArgs *args) {\r
+    UiToolbarContentToggleItem* item = malloc(sizeof(UiToolbarContentToggleItem));\r
+    item->item.type = UI_TOOLBAR_CONTENT_TOGGLEITEM;\r
+    item->args = contenttoggleitemargs_copy(args, &item->nstates, &item->nvstates);\r
+    cxMapPut(toolbar_items, name, item);\r
+}\r
+\r
 static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args, size_t *nvstates) {\r
     UiToolbarMenuArgs newargs;\r
     newargs.label = nl_strdup(args->label);\r
index 9ae60f07cb5b0c04a0cd70b2ae0bcd70441ae49f..dd792644c20b5d7ec5b50e6ff3bdc11befb31d9e 100644 (file)
 extern "C" {\r
 #endif\r
 \r
-typedef struct UiToolbarItemI      UiToolbarItemI;\r
+typedef struct UiToolbarItemI               UiToolbarItemI;\r
 \r
-typedef struct UiToolbarItem       UiToolbarItem;\r
-typedef struct UiToolbarToggleItem UiToolbarToggleItem;\r
+typedef struct UiToolbarItem                UiToolbarItem;\r
+typedef struct UiToolbarToggleItem          UiToolbarToggleItem;\r
+typedef struct UiToolbarContentToggleItem   UiToolbarContentToggleItem;\r
 \r
-typedef struct UiToolbarMenuItem   UiToolbarMenuItem;\r
+typedef struct UiToolbarMenuItem            UiToolbarMenuItem;\r
 \r
 enum UiToolbarItemType {\r
     UI_TOOLBAR_ITEM = 0,\r
     UI_TOOLBAR_TOGGLEITEM,\r
+    UI_TOOLBAR_CONTENT_TOGGLEITEM,\r
     UI_TOOLBAR_MENU\r
 };\r
 \r
@@ -73,6 +75,13 @@ struct UiToolbarToggleItem {
     size_t nvstates;\r
 };\r
 \r
+struct UiToolbarContentToggleItem {\r
+    UiToolbarItemI item;\r
+    UiToolbarContentToggleItemArgs args;\r
+    size_t nstates;\r
+    size_t nvstates;\r
+};\r
+\r
 struct UiToolbarMenuItem {\r
     UiToolbarItemI item;\r
     UiMenu menu;\r
index e0ecf515f16d06daa3c292c583c0042b248f0324..fd1712bf8bec715599d71297c7f221bd32b2655d 100644 (file)
@@ -100,7 +100,9 @@ void ui_notify_evt(UiObserver *observer, UiEvent *event) {
 /* --------------------------- UiList --------------------------- */
 
 void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
-    list->data = cxArrayListCreate(ctx->mp->allocator, CX_STORE_POINTERS, 32);
+    const CxAllocator *a = ctx ? ctx->allocator : cxDefaultAllocator;
+    list->destroy = uic_ucx_list_destroy;
+    list->data = cxArrayListCreate(a, CX_STORE_POINTERS, 32);
     list->first = ui_list_first;
     list->next = ui_list_next;
     list->get = ui_list_get;
@@ -109,7 +111,6 @@ void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
 
 void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused) {
     cxListFree(list->data);
-    ui_free(ctx, list);
 }
 
 UiList* ui_list_new(UiContext *ctx, const char *name) {
@@ -117,11 +118,12 @@ UiList* ui_list_new(UiContext *ctx, const char *name) {
 }
 
 UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) {
-    UiList *list = cxMalloc(ctx->mp->allocator, sizeof(UiList));
+    UiList *list = ui_malloc(ctx, sizeof(UiList));
     memset(list, 0, sizeof(UiList));
     listinit(ctx, list, userdata);
+    list->save_selection = TRUE;
     
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_LIST, list);
     }
     
@@ -129,12 +131,15 @@ UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listini
 }
 
 void ui_list_free(UiContext *ctx, UiList *list) {
-    if(!default_list_destroy) {
+    if(list->destroy) {
+        list->destroy(ctx, list, NULL);
+    } else if(!default_list_destroy) {
         uic_ucx_list_destroy(ctx, list, NULL);
     } else {
         default_list_destroy(ctx, list, default_list_destroy_userdata);
     }
-    
+    ui_list_selection_free(list->saved_selection);
+    ui_free(ctx, list);
 }
 
 void* ui_list_first(UiList *list) {
@@ -168,6 +173,10 @@ void ui_list_prepend(UiList *list, void *data) {
     cxListInsert(list->data, 0, data);
 }
 
+void ui_list_insert(UiList *list, int index, void *data) {
+    cxListInsert(list->data, (size_t)index, data);
+}
+
 void ui_list_remove(UiList *list, int i) {
     if(i >= 0) {
         cxListRemove(list->data, i);
@@ -212,6 +221,11 @@ void ui_list_notify(UiList *list) {
     ui_notify(list->observers, list);
 }
 
+void ui_list_clear_saved_selection(UiList *list) {
+    ui_list_selection_free(list->saved_selection);
+    list->saved_selection = NULL;
+}
+
 
 typedef struct {
     int  type;
@@ -221,6 +235,7 @@ typedef struct {
 UiModel* ui_model(UiContext *ctx, ...) {
     UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
     info->ctx = ctx;
+    info->ref = 1;
     
     va_list ap;
     va_start(ap, ctx);
@@ -272,6 +287,7 @@ static void model_notify_observer(UiModel *model, int insert, int delete) {
 UiModel* ui_model_new(UiContext *ctx) {
     UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
     info->ctx = ctx;
+    info->ref = 1;
     info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE;
     info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType));
     info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*));
@@ -368,7 +384,7 @@ void ui_model_remove_observer(UiModel *model, void *data) {
 
 void ui_model_free(UiModel *mi) {
     UiContext *ctx = mi->ctx;
-    const CxAllocator* a = ctx->allocator;
+    const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
     for(int i=0;i<mi->columns;i++) {
         ui_free(ctx, mi->titles[i]);
     }
@@ -390,7 +406,7 @@ void ui_model_free(UiModel *mi) {
 UiInteger* ui_int_new(UiContext *ctx, const char *name) {
     UiInteger *i = ui_malloc(ctx, sizeof(UiInteger));
     memset(i, 0, sizeof(UiInteger));
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_INTEGER, i);
     }
     return i;
@@ -399,7 +415,7 @@ UiInteger* ui_int_new(UiContext *ctx, const char *name) {
 UiDouble* ui_double_new(UiContext *ctx, const char *name) {
     UiDouble *d = ui_malloc(ctx, sizeof(UiDouble));
     memset(d, 0, sizeof(UiDouble));
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_DOUBLE, d);
     }
     return d;
@@ -415,13 +431,16 @@ UiString* ui_string_new(UiContext *ctx, const char *name) {
     UiString *s = ui_malloc(ctx, sizeof(UiString));
     memset(s, 0, sizeof(UiString));
     ui_set_destructor(s, (ui_destructor_func)string_destroy);
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_STRING, s);
     }
     return s;
 }
 
 static void text_destroy(UiText *t) {
+    if(t->value.free) {
+        t->value.free(t->value.ptr);
+    }
     if(t->destroy) {
         t->destroy(t);
     }
@@ -431,7 +450,7 @@ UiText* ui_text_new(UiContext *ctx, const char *name) {
     UiText *t = ui_malloc(ctx, sizeof(UiText));
     memset(t, 0, sizeof(UiText));
     ui_set_destructor(t, (ui_destructor_func)text_destroy);
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_TEXT, t);
     }
     return t;
@@ -440,7 +459,7 @@ UiText* ui_text_new(UiContext *ctx, const char *name) {
 UiRange* ui_range_new(UiContext *ctx, const char *name) {
     UiRange *r = ui_malloc(ctx, sizeof(UiRange));
     memset(r, 0, sizeof(UiRange));
-    if(name) {
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_RANGE, r);
     }
     return r;
@@ -455,8 +474,10 @@ static void generic_destroy(UiGeneric *g) {
 UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
     UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
     memset(g, 0, sizeof(UiGeneric));
-    ui_set_destructor(g, (ui_destructor_func)generic_destroy);
-    if(name) {
+    if(ctx) {
+        ui_set_destructor(g, (ui_destructor_func)generic_destroy);
+    }
+    if(name && ctx) {
         uic_reg_var(ctx, name, UI_VAR_GENERIC, g);
     }
     return g;
@@ -684,6 +705,7 @@ void uic_text_copy(UiText *from, UiText *to) {
     to->selection = from->selection;
     to->length = from->length;
     to->remove = from->remove;
+    to->setreadonly = from->setreadonly;
     to->restore = from->restore;
     to->save = from->save;
     to->destroy = from->destroy;
@@ -742,6 +764,9 @@ void uic_range_save(UiRange *r) {
 
 void uic_generic_save(UiGeneric *g) {
     if(!g->obj) return;
+    // TODO: this leaks memory
+    // we can't just use get on Generic and ignore the result
+    // probably a separate save method is required
     g->get(g);
 }
 
@@ -765,6 +790,14 @@ void uic_string_unbind(UiString *s) {
 }
 
 void uic_text_unbind(UiText *t) {
+    t->obj = NULL;
+    if(t->data1 && t->datatype == UI_TEXT_TYPE_BUFFER) {
+        // the binding functions all work with t->data1, not t->obj
+        // and we don't want to NULL them, because they will be still
+        // functional even without a widget binding
+        return;
+    }
+    
     t->set = NULL;
     t->get = NULL;
     t->getsubstr = NULL;
@@ -772,11 +805,12 @@ void uic_text_unbind(UiText *t) {
     t->replace = NULL;
     t->setposition = NULL;
     t->position = NULL;
+    t->showposition = NULL;
     t->selection = NULL;
     t->setselection = NULL;
     t->length = NULL;
     t->remove = NULL;
-    t->obj = NULL;
+    t->setreadonly = NULL;
 }
 
 void uic_range_unbind(UiRange *r) {
@@ -802,6 +836,23 @@ void uic_generic_unbind(UiGeneric *g) {
 }
 
 
+
+UiListSelection* ui_list_get_selection_allocated(UiList *list) {
+    UiListSelection *sel = malloc(sizeof(UiListSelection));
+    *sel = ui_list_get_selection(list);
+    return sel;
+    
+}
+
+void ui_list_selection_free(UiListSelection *sel) {
+    if(!sel) {
+        return;
+    }
+    ui_listselection_free(*sel);
+    free(sel);
+}
+
+
 UIEXPORT int ui_list_getselection(UiList *list) {
     int selection = -1;
     if (list->getselection) {
@@ -935,6 +986,10 @@ void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) {
     default_list_destroy_userdata = userdata;
 }
 
+UIEXPORT void ui_list_class_set_destructor(UiList *list, ui_list_destroy_func destroy) {
+    list->destroy = destroy;
+}
+
 void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
     list->first = first;
 }
@@ -958,3 +1013,85 @@ void ui_list_class_set_data(UiList *list, void *data) {
 void ui_list_class_set_iter(UiList *list, void *iter) {
     list->iter = iter;
 }
+
+/* ---------------- Text functions ---------------- */
+
+char* ui_text_getsubstr(UiText *text, int begin, int end) {
+    if(text->getsubstr) {
+        return text->getsubstr(text, begin, end);
+    } else {
+        return NULL;
+    }
+}
+
+void  ui_text_insert(UiText *text, int pos, const char *str) {
+    if(text->insert) {
+        text->insert(text, pos, str);
+    }
+}
+
+void  ui_text_replace(UiText *text, int begin, int end, const char *str) {
+    if(text->replace) {
+        text->replace(text, begin, end, str);
+    }
+}
+
+void  ui_text_setposition(UiText *text, int pos) {
+    if(text->setposition) {
+        text->setposition(text, pos);
+    }
+}
+
+int   ui_text_position(UiText *text) {
+    if(text->position) {
+        return text->position(text);
+    } else {
+        return 0;
+    }
+}
+
+void  ui_text_showposition(UiText *text, int pos) {
+    if(text->showposition) {
+        text->showposition(text, pos);
+    }
+}
+
+void  ui_text_setselection(UiText *text, int begin, int end) {
+    if(text->setselection) {
+        text->setselection(text, begin, end);
+    }
+}
+
+void  ui_text_selection(UiText *text, int *begin, int *end) {
+    if(text->selection) {
+        text->selection(text, begin, end);
+    } else {
+        if(begin) {
+            *begin = 0;
+        }
+        if(end) {
+            *end = 0;
+        }
+    }
+}
+
+int   ui_text_length(UiText *text) {
+    if(text->length) {
+        return text->length(text);
+    } else {
+        return 0;
+    }
+}
+void  ui_text_remove(UiText *text, int begin, int end) {
+    if(text->remove) {
+        text->remove(text, begin, end);
+    }
+}
+
+void  ui_text_setreadonly(UiText *text, int readonly) {
+    if(text->setreadonly) {
+        text->setreadonly(text, readonly);
+    } else {
+        text->readonly = readonly;
+    }
+}
index 2f4a5249ea8bd3e53de2e1f5608c2ba2e4054e35..8723ce0dc7685e4d1b54bd5df9ce3fc9852c55cf 100644 (file)
@@ -61,6 +61,9 @@ void uic_range_unbind(UiRange *r);
 void uic_list_unbind(UiList *l);
 void uic_generic_unbind(UiGeneric *g);
 
+UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list);
+UIEXPORT void ui_list_selection_free(UiListSelection *sel);
+
 void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObserver *observer);
   
 #ifdef __cplusplus
diff --git a/ui/common/ucx_properties.c b/ui/common/ucx_properties.c
deleted file mode 100644 (file)
index 21e9341..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ucx_properties.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-UcxProperties *ucx_properties_new() {
-    UcxProperties *parser = (UcxProperties*)malloc(
-            sizeof(UcxProperties));
-    if(!parser) {
-        return NULL;
-    }
-    
-    parser->buffer = NULL;
-    parser->buflen = 0;
-    parser->pos = 0;
-    parser->tmp = NULL;
-    parser->tmplen = 0;
-    parser->tmpcap = 0;
-    parser->error = 0;
-    parser->delimiter = '=';
-    parser->comment1 = '#';
-    parser->comment2 = 0;
-    parser->comment3 = 0;   
-    
-    return parser;
-}
-
-void ucx_properties_free(UcxProperties *parser) {
-    if(parser->tmp) {
-        free(parser->tmp);
-    }
-    free(parser);
-}
-
-void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) {
-    parser->buffer = buf;
-    parser->buflen = len;
-    parser->pos = 0;
-}
-
-static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) {
-    if(parser->tmpcap - parser->tmplen < len) {
-        size_t newcap = parser->tmpcap + len + 64;
-        parser->tmp = (char*)realloc(parser->tmp, newcap);
-        parser->tmpcap = newcap;
-    }
-    memcpy(parser->tmp + parser->tmplen, buf, len);
-    parser->tmplen += len;
-}
-
-int ucx_properties_next(UcxProperties *parser, cxstring *name, cxstring *value)  {   
-    if(parser->tmplen > 0) {
-        char *buf = parser->buffer + parser->pos;
-        size_t len = parser->buflen - parser->pos;
-        cxstring str = cx_strn(buf, len);
-        cxstring nl = cx_strchr(str, '\n');
-        if(nl.ptr) {
-            size_t newlen = (size_t)(nl.ptr - buf) + 1;
-            parser_tmp_append(parser, buf, newlen);
-            // the tmp buffer contains exactly one line now
-            
-            char *orig_buf = parser->buffer;
-            size_t orig_len = parser->buflen;
-            
-            parser->buffer = parser->tmp;
-            parser->buflen = parser->tmplen;
-            parser->pos = 0;    
-            parser->tmp = NULL;
-            parser->tmpcap = 0;
-            parser->tmplen = 0;
-            // run ucx_properties_next with the tmp buffer as main buffer
-            int ret = ucx_properties_next(parser, name, value);
-            
-            // restore original buffer
-            parser->tmp = parser->buffer;
-            parser->buffer = orig_buf;
-            parser->buflen = orig_len;
-            parser->pos = newlen;
-            
-            /*
-             * if ret == 0 the tmp buffer contained just space or a comment
-             * we parse again with the original buffer to get a name/value
-             * or a new tmp buffer
-             */
-            return ret ? ret : ucx_properties_next(parser, name, value);
-        } else {
-            parser_tmp_append(parser, buf, len);
-            return 0;
-        }
-    } else if(parser->tmp) {
-        free(parser->tmp);
-        parser->tmp = NULL;
-    }
-    
-    char comment1 = parser->comment1;
-    char comment2 = parser->comment2;
-    char comment3 = parser->comment3;
-    char delimiter = parser->delimiter;
-    
-    // get one line and parse it
-    while(parser->pos < parser->buflen) {
-        char *buf = parser->buffer + parser->pos;
-        size_t len = parser->buflen - parser->pos;
-        
-        /*
-         * First we check if we have at least one line. We also get indices of
-         * delimiter and comment chars
-         */
-        size_t delimiter_index = 0;
-        size_t comment_index = 0;
-        int has_comment = 0;
-
-        size_t i = 0;
-        char c = 0;
-        for(;i<len;i++) {
-            c = buf[i];
-            if(c == comment1 || c == comment2 || c == comment3) {
-                if(comment_index == 0) {
-                    comment_index = i;
-                    has_comment = 1;
-                }
-            } else if(c == delimiter) {
-                if(delimiter_index == 0 && !has_comment) {
-                    delimiter_index = i;
-                }
-            } else if(c == '\n') {
-                break;
-            }
-        }
-
-        if(c != '\n') {
-            // we don't have enough data for a line
-            // store remaining bytes in temporary buffer for next round
-            parser->tmpcap = len + 128;
-            parser->tmp = (char*)malloc(parser->tmpcap);
-            parser->tmplen = len;
-            memcpy(parser->tmp, buf, len);
-            return 0;
-        }
-        
-        cxstring line = has_comment ? cx_strn(buf, comment_index) : cx_strn(buf, i);
-        // check line
-        if(delimiter_index == 0) {
-            line = cx_strtrim(line);
-            if(line.length != 0) {
-                parser->error = 1;
-            }
-        } else {
-            cxstring n = cx_strn(buf, delimiter_index);
-            cxstring v = cx_strn(
-                    buf + delimiter_index + 1,
-                    line.length - delimiter_index - 1); 
-            n = cx_strtrim(n);
-            v = cx_strtrim(v);
-            if(n.length != 0 || v.length != 0) {
-                *name = n;
-                *value = v;
-                parser->pos += i + 1;
-                return 1;
-            } else {
-                parser->error = 1;
-            }
-        }
-        
-        parser->pos += i + 1;
-    }
-    
-    return 0;
-}
-
-int ucx_properties2map(UcxProperties *parser, CxMap *map) {
-    cxstring name;
-    cxstring value;
-    while(ucx_properties_next(parser, &name, &value)) {
-        cxmutstr mutvalue = cx_strdup_a(map->collection.allocator, value);
-        if(!mutvalue.ptr) {
-            return 1;
-        }
-        if(cxMapPut(map, cx_hash_key_cxstr(name), mutvalue.ptr)) {
-            cxFree(map->collection.allocator, mutvalue.ptr);
-            return 1;
-        }
-    }
-    if (parser->error) {
-        return parser->error;
-    } else {
-        return 0;
-    }
-}
-
-// buffer size is documented - change doc, when you change bufsize!
-#define UCX_PROPLOAD_BUFSIZE  1024
-int ucx_properties_load(CxMap *map, FILE *file) {
-    UcxProperties *parser = ucx_properties_new();
-    if(!(parser && map && file)) {
-        return 1;
-    }
-    
-    int error = 0;
-    size_t r;
-    char buf[UCX_PROPLOAD_BUFSIZE];
-    while((r = fread(buf, 1, UCX_PROPLOAD_BUFSIZE, file)) != 0) {
-        ucx_properties_fill(parser, buf, r);
-        error = ucx_properties2map(parser, map);
-        if (error) {
-            break;
-        }
-    }
-    ucx_properties_free(parser);
-    return error;
-}
-
-int ucx_properties_store(CxMap *map, FILE *file) {
-    CxMapIterator iter = cxMapIterator(map);
-    cxstring value;
-    size_t written;
-
-    cx_foreach(CxMapEntry *, v, iter) {
-        value = cx_str(v->value);
-
-        written = 0;
-        written += fwrite(v->key->data, 1, v->key->len, file);
-        written += fwrite(" = ", 1, 3, file);
-        written += fwrite(value.ptr, 1, value.length, file);
-        written += fwrite("\n", 1, 1, file);
-
-        if (written != v->key->len + value.length + 4) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
diff --git a/ui/common/ucx_properties.h b/ui/common/ucx_properties.h
deleted file mode 100644 (file)
index cfb4359..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-/**
- * @file properties.h
- * 
- * Load / store utilities for properties files.
- * 
- * @author Mike Becker
- * @author Olaf Wintermann
- */
-
-#ifndef UCX_PROPERTIES_H
-#define        UCX_PROPERTIES_H
-
-#include <cx/hash_map.h>
-#include <cx/string.h>
-
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * UcxProperties object for parsing properties data.
- * Most of the fields are for internal use only. You may configure the
- * properties parser, e.g. by changing the used delimiter or specifying 
- * up to three different characters that shall introduce comments.
- */
-typedef struct {
-    /**
-     * Input buffer (don't set manually).
-     * Automatically set by calls to ucx_properties_fill().
-     */
-    char   *buffer;
-    
-    /**
-     * Length of the input buffer (don't set manually).
-     * Automatically set by calls to ucx_properties_fill().
-     */
-    size_t buflen;
-    
-    /**
-     * Current buffer position (don't set manually).
-     * Used by ucx_properties_next().
-     */
-    size_t pos;
-    
-    /**
-     * Internal temporary buffer (don't set manually).
-     * Used by ucx_properties_next().
-     */
-    char   *tmp;
-    
-    /**
-     * Internal temporary buffer length (don't set manually).
-     * Used by ucx_properties_next().
-     */
-    size_t tmplen;
-    
-    /**
-     * Internal temporary buffer capacity (don't set manually).
-     * Used by ucx_properties_next().
-     */
-    size_t tmpcap;
-    
-    /**
-     * Parser error code.
-     * This is always 0 on success and a nonzero value on syntax errors.
-     * The value is set by ucx_properties_next().
-     */
-    int    error;
-    
-    /**
-     * The delimiter that shall be used.
-     * This is '=' by default.
-     */
-    char   delimiter;
-    
-    /**
-     * The first comment character.
-     * This is '#' by default.
-     */
-    char   comment1;
-    
-    /**
-     * The second comment character.
-     * This is not set by default.
-     */
-    char   comment2;
-    
-    /**
-     * The third comment character.
-     * This is not set by default.
-     */
-    char   comment3;
-} UcxProperties;
-
-
-/**
- * Constructs a new UcxProperties object.
- * @return a pointer to the new UcxProperties object
- */
-UcxProperties *ucx_properties_new();
-
-/**
- * Destroys a UcxProperties object.
- * @param prop the UcxProperties object to destroy
- */
-void ucx_properties_free(UcxProperties *prop);
-
-/**
- * Sets the input buffer for the properties parser.
- * 
- * After calling this function, you may parse the data by calling
- * ucx_properties_next() until it returns 0. The function ucx_properties2map()
- * is a convenience function that reads as much data as possible by using this
- * function.
- * 
- * 
- * @param prop the UcxProperties object
- * @param buf a pointer to the new buffer
- * @param len the payload length of the buffer
- * @see ucx_properties_next()
- * @see ucx_properties2map()
- */
-void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len);
-
-/**
- * Retrieves the next key/value-pair.
- * 
- * This function returns a nonzero value as long as there are key/value-pairs
- * found. If no more key/value-pairs are found, you may refill the input buffer
- * with ucx_properties_fill().
- * 
- * <b>Attention:</b> the cxstring.ptr pointers of the output parameters point to
- * memory within the input buffer of the parser and will get invalid some time.
- * If you want long term copies of the key/value-pairs, use sstrdup() after
- * calling this function.
- * 
- * @param prop the UcxProperties object
- * @param name a pointer to the cxstring that shall contain the property name
- * @param value a pointer to the cxstring that shall contain the property value
- * @return Nonzero, if a key/value-pair was successfully retrieved
- * @see ucx_properties_fill()
- */
-int ucx_properties_next(UcxProperties *prop, cxstring *name, cxstring *value);
-
-/**
- * Retrieves all available key/value-pairs and puts them into a UcxMap.
- * 
- * This is done by successive calls to ucx_properties_next() until no more
- * key/value-pairs can be retrieved.
- * 
- * The memory for the map values is allocated by the map's own allocator.
- * 
- * @param prop the UcxProperties object
- * @param map the target map
- * @return The UcxProperties.error code (i.e. 0 on success).
- * @see ucx_properties_fill()
- * @see UcxMap.allocator
- */
-int ucx_properties2map(UcxProperties *prop, CxMap *map);
-
-/**
- * Loads a properties file to a UcxMap.
- * 
- * This is a convenience function that reads data from an input
- * stream until the end of the stream is reached.
- * 
- * @param map the map object to write the key/value-pairs to
- * @param file the <code>FILE*</code> stream to read from
- * @return 0 on success, or a non-zero value on error
- * 
- * @see ucx_properties_fill()
- * @see ucx_properties2map()
- */
-int ucx_properties_load(CxMap *map, FILE *file);
-
-/**
- * Stores a UcxMap to a file.
- * 
- * The key/value-pairs are written by using the following format:
- * 
- * <code>[key] = [value]\\n</code>
- * 
- * @param map the map to store
- * @param file the <code>FILE*</code> stream to write to
- * @return 0 on success, or a non-zero value on error
- */
-int ucx_properties_store(CxMap *map, FILE *file);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UCX_PROPERTIES_H */
-
index 575dd2989f65b13ddec22503fd89ad0c612f3947..29af77edfbb9296a7f98c536ee9529f6f99b9987 100644 (file)
@@ -45,6 +45,40 @@ void ui_object_set_windowdata(UiObject *obj, void *windowdata) {
     obj->window = windowdata;
 }
 
+void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata) {
+    obj->onclose = callback;
+    obj->onclosedata = userdata;
+}
+
+static int obj_unref(void *ptr) {
+    ui_object_unref(ptr);
+    return 0;
+}
+
+void ui_mainthread_object_unref(UiObject *obj) {
+    // TODO: detect if this is already the main thread and call
+    //       ui_object_unref directly in that case
+    ui_call_mainthread(obj_unref, obj);
+}
+
+static int doc_unref(void *ptr) {
+    ui_document_unref(ptr);
+    return 0;
+}
+
+void ui_mainthread_document_unref(void *doc) {
+    // TODO: see ui_mainthread_object_unref
+    ui_call_mainthread(doc_unref, doc);
+}
+
+static int app_unref(void *unused) {
+    ui_app_unref();
+    return 0;
+}
+
+void ui_mainthread_app_unref() {
+    ui_call_mainthread(app_unref, NULL);
+}
 
 /* ---------------------------- UiList ---------------------------- */
 
@@ -64,6 +98,13 @@ void ui_list_set_iter(UiList *list, void *iter) {
     list->iter = iter;
 }
 
+void ui_list_set_save_selection(UiList *list, UiBool value) {
+    list->save_selection = value;
+}
+
+UiBool ui_list_get_save_selection(UiList *list) {
+    return list->save_selection;
+}
 
 /* ------------------------------ UiSublist ------------------------------ */
 
@@ -209,6 +250,17 @@ int ui_event_get_set(UiEvent *event) {
 }
 
 
+/* ---------------------------- UiTypedObj ---------------------------- */
+
+void* ui_typed_obj_get_ptr(UiTypedObj *obj) {
+    return obj->ptr;
+}
+
+uint64_t ui_typed_obj_get_type(UiTypedObj *obj) {
+    return obj->type;
+}
+
+
 /* ------------------------- SubListItem (public) ------------------------- */
 
 void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon) {
@@ -241,13 +293,6 @@ void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) {
 
 /* ---------------------------- UiListSelection ---------------------------- */
 
-UiListSelection* ui_list_get_selection_allocated(UiList *list) {
-    UiListSelection *sel = malloc(sizeof(UiListSelection));
-    *sel = ui_list_get_selection(list);
-    return sel;
-    
-}
-
 int ui_list_selection_get_count(UiListSelection *sel) {
     return sel->count;
 }
@@ -265,9 +310,27 @@ UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num)
     }
 }
 
-void ui_list_selection_free(UiListSelection *sel) {
-    ui_listselection_free(*sel);
-    free(sel);
+
+/* -------------------------- UiTextChangedEvent -------------------------- */
+
+int ui_text_change_event_get_type(UiTextChangeEventData *event) {
+    return event->type;
+}
+
+int ui_text_change_event_get_begin(UiTextChangeEventData *event) {
+    return event->begin;
+}
+
+int ui_text_change_event_get_end(UiTextChangeEventData *event) {
+    return event->end;
+}
+
+const char* ui_text_change_event_get_text(UiTextChangeEventData *event) {
+    return event->text;
+}
+
+int ui_text_change_event_get_length(UiTextChangeEventData *event) {
+    return event->length;
 }
 
 /* ---------------------------- UiFileList ---------------------------- */
index 37f2f38a9f4de88d7dc584e2b178a5bc0bac1b57..2883e56d56ce234b2931be09b74687867f1b0ec1 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "../ui/toolkit.h"
 #include "../ui/list.h"
+#include "../ui/text.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -39,10 +40,17 @@ extern "C" {
 UIEXPORT UiContext* ui_object_get_context(UiObject *obj);
 UIEXPORT void* ui_object_get_windowdata(UiObject *obj);
 UIEXPORT void ui_object_set_windowdata(UiObject *obj, void *windowdata);
+UIEXPORT void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata);
+
+UIEXPORT void ui_mainthread_object_unref(UiObject *obj);
+UIEXPORT void ui_mainthread_document_unref(void *doc);
+UIEXPORT void ui_mainthread_app_unref();
 
 UIEXPORT void* ui_list_get_data(UiList *list);
 UIEXPORT void* ui_list_get_iter(UiList *list);
 UIEXPORT void ui_list_set_iter(UiList *list, void *iter);
+UIEXPORT void ui_list_set_save_selection(UiList *list, UiBool value);
+UIEXPORT UiBool ui_list_get_save_selection(UiList *list);
 
 UIEXPORT UiSubList* ui_sublist_new(void);
 UIEXPORT void ui_sublist_set_value(UiSubList *sublist, UiList *value);
@@ -76,11 +84,18 @@ UIEXPORT int ui_event_get_eventdatatype(UiEvent *event);
 UIEXPORT int ui_event_get_int(UiEvent *event);
 UIEXPORT int ui_event_get_set(UiEvent *event);
 
-UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list);
+UIEXPORT void* ui_typed_obj_get_ptr(UiTypedObj *obj);
+UIEXPORT uint64_t ui_typed_obj_get_type(UiTypedObj *obj);
+
 UIEXPORT int ui_list_selection_get_count(UiListSelection *sel);
 UIEXPORT int* ui_list_selection_get_rows(UiListSelection *sel);
 UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num);
-UIEXPORT void ui_list_selection_free(UiListSelection *sel);
+
+UIEXPORT int ui_text_change_event_get_type(UiTextChangeEventData *event);
+UIEXPORT int ui_text_change_event_get_begin(UiTextChangeEventData *event);
+UIEXPORT int ui_text_change_event_get_end(UiTextChangeEventData *event);
+UIEXPORT const char* ui_text_change_event_get_text(UiTextChangeEventData *event);
+UIEXPORT int ui_text_change_event_get_length(UiTextChangeEventData *event);
 
 UIEXPORT int ui_filelist_count(UiFileList *flist);
 UIEXPORT char* ui_filelist_get(UiFileList *flist, int index);
index d1979fb679363275ee0324300dc598bc6a5a4c83..8f43a1b5d621d8ac54e5591ef325c0d29abdb853 100644 (file)
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-$(GTK_OBJPRE)%.o: gtk/%.c
-       $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
-       
 $(UI_LIB): $(OBJ)
        $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)       
 
 $(UI_SHLIB): $(OBJ)
        $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
+
+FORCE:
+
+$(GTK_OBJPRE)action.o: gtk/action.c gtk/action.h gtk/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)button.o: gtk/button.c gtk/button.h gtk/../ui/toolkit.h \
+ gtk/../ui/button.h gtk/../ui/toolkit.h gtk/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/container.h \
+ gtk/../ui/container.h gtk/widget.h gtk/../ui/widget.h \
+ gtk/../common/action.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)container.o: gtk/container.c gtk/container.h \
+ gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \
+ gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/headerbar.h \
+ gtk/../ui/toolbar.h gtk/../common/toolbar.h \
+ gtk/../common/../ui/toolbar.h gtk/../common/menu.h \
+ gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/container.h gtk/../common/../ui/container.h \
+ gtk/../ui/properties.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)display.o: gtk/display.c gtk/display.h gtk/../ui/toolkit.h \
+ gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/container.h \
+ gtk/../ui/container.h gtk/../ui/toolkit.h gtk/../ui/display.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)dnd.o: gtk/dnd.c gtk/dnd.h gtk/../ui/dnd.h \
+ gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)draw_cairo.o: gtk/draw_cairo.c gtk/container.h \
+ gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \
+ gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/draw_cairo.h \
+ gtk/graphics.h gtk/../ui/graphics.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)draw_gdk.o: gtk/draw_gdk.c gtk/container.h \
+ gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \
+ gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/draw_gdk.h \
+ gtk/graphics.h gtk/../ui/graphics.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)entry.o: gtk/entry.c gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/container.h gtk/../ui/toolkit.h \
+ gtk/../ui/container.h gtk/../ui/toolkit.h gtk/toolkit.h gtk/entry.h \
+ gtk/../ui/entry.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)graphics.o: gtk/graphics.c gtk/graphics.h \
+ gtk/../ui/graphics.h gtk/../ui/toolkit.h gtk/toolkit.h \
+ gtk/../ui/toolkit.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/container.h gtk/../ui/container.h \
+ gtk/draw_cairo.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)headerbar.o: gtk/headerbar.c gtk/headerbar.h gtk/toolkit.h \
+ gtk/../ui/toolkit.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/../ui/toolbar.h gtk/../ui/toolkit.h \
+ gtk/../common/toolbar.h gtk/../common/../ui/toolbar.h \
+ gtk/../common/menu.h gtk/../common/../ui/menu.h \
+ gtk/../common/../ui/toolkit.h gtk/button.h gtk/../ui/button.h gtk/menu.h \
+ gtk/../ui/menu.h gtk/../common/menu.h gtk/../ui/properties.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)icon.o: gtk/icon.c gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/icon.h \
+ gtk/../ui/icons.h gtk/../ui/toolkit.h gtk/../common/properties.h \
+ gtk/../common/../ui/properties.h gtk/../common/../ui/toolkit.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)image.o: gtk/image.c gtk/image.h gtk/../ui/image.h \
+ gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/container.h \
+ gtk/../ui/container.h gtk/menu.h gtk/../ui/menu.h gtk/../common/menu.h \
+ gtk/../common/../ui/menu.h gtk/widget.h gtk/../ui/widget.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)list.o: gtk/list.c gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/../common/action.h gtk/container.h \
+ gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \
+ gtk/toolkit.h gtk/list.h gtk/../ui/list.h gtk/button.h \
+ gtk/../ui/button.h gtk/icon.h gtk/../ui/icons.h gtk/menu.h \
+ gtk/../ui/menu.h gtk/../common/menu.h gtk/../common/../ui/menu.h \
+ gtk/dnd.h gtk/../ui/dnd.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)menu.o: gtk/menu.c gtk/menu.h gtk/../ui/menu.h \
+ gtk/../ui/toolkit.h gtk/../common/menu.h gtk/../common/../ui/menu.h \
+ gtk/toolkit.h gtk/../ui/toolkit.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/widget.h gtk/../ui/widget.h \
+ gtk/../common/types.h gtk/../common/action.h gtk/../ui/properties.h \
+ gtk/../ui/window.h gtk/container.h gtk/../ui/container.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)range.o: gtk/range.c gtk/range.h gtk/toolkit.h \
+ gtk/../ui/toolkit.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h gtk/../ui/range.h gtk/../ui/toolkit.h \
+ gtk/container.h gtk/../ui/container.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)text.o: gtk/text.c gtk/text.h gtk/../ui/text.h \
+ gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/container.h \
+ gtk/../ui/container.h gtk/widget.h gtk/../ui/widget.h \
+ gtk/../common/types.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)toolbar.o: gtk/toolbar.c gtk/toolbar.h gtk/../ui/toolbar.h \
+ gtk/../ui/toolkit.h gtk/../common/toolbar.h \
+ gtk/../common/../ui/toolbar.h gtk/../common/menu.h \
+ gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h gtk/list.h \
+ gtk/../ui/list.h gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/menu.h \
+ gtk/../ui/menu.h gtk/../common/menu.h gtk/button.h gtk/../ui/button.h \
+ gtk/icon.h gtk/../ui/icons.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)toolkit.o: gtk/toolkit.c gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/toolbar.h \
+ gtk/../ui/toolbar.h gtk/../ui/toolkit.h gtk/../common/toolbar.h \
+ gtk/../common/../ui/toolbar.h gtk/../common/menu.h \
+ gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h gtk/list.h \
+ gtk/../ui/list.h gtk/window.h gtk/icon.h gtk/../ui/icons.h \
+ gtk/../common/document.h gtk/../common/context.h \
+ gtk/../common/properties.h gtk/../common/../ui/properties.h \
+ gtk/../common/menu.h gtk/../common/threadpool.h gtk/../common/app.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)webview.o: gtk/webview.c gtk/toolkit.h gtk/../ui/toolkit.h \
+ gtk/../common/context.h gtk/../common/../ui/toolkit.h \
+ gtk/../common/action.h gtk/../common/object.h gtk/container.h \
+ gtk/../ui/container.h gtk/../ui/toolkit.h gtk/webview.h \
+ gtk/../ui/webview.h gtk/widget.h gtk/../ui/widget.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)widget.o: gtk/widget.c gtk/widget.h gtk/../ui/widget.h \
+ gtk/../ui/toolkit.h gtk/container.h gtk/../ui/toolkit.h \
+ gtk/../ui/container.h gtk/toolkit.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/object.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
+$(GTK_OBJPRE)window.o: gtk/window.c gtk/../ui/window.h \
+ gtk/../ui/toolkit.h gtk/../ui/properties.h gtk/../common/context.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/action.h \
+ gtk/../common/menu.h gtk/../common/../ui/menu.h \
+ gtk/../common/../ui/toolkit.h gtk/../common/toolbar.h \
+ gtk/../common/../ui/toolbar.h gtk/../common/menu.h gtk/../common/utils.h \
+ gtk/../common/../ui/text.h gtk/menu.h gtk/../ui/menu.h gtk/toolkit.h \
+ gtk/../ui/toolkit.h gtk/../common/object.h gtk/toolbar.h \
+ gtk/../ui/toolbar.h gtk/list.h gtk/../ui/list.h gtk/container.h \
+ gtk/../ui/container.h gtk/headerbar.h gtk/button.h gtk/../ui/button.h \
+ gtk/window.h
+       $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $<
+
diff --git a/ui/gtk/action.c b/ui/gtk/action.c
new file mode 100644 (file)
index 0000000..80f0a42
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "action.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+/* ------------------------------ public API ------------------------------ */
+
+void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata) {
+    uic_add_action(ctx, name, callback, userdata, NULL, NULL);
+}
+
+void ui_add_action_with_accelerator(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text)
+{
+    uic_add_action(ctx, name, callback, userdata, accelerator, accelerator_text);
+    
+    // TODO: accelerator
+}
diff --git a/ui/gtk/action.h b/ui/gtk/action.h
new file mode 100644 (file)
index 0000000..d13d3de
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ACTION_H
+#define ACTION_H
+
+#include "../ui/toolkit.h"
+#include "../common/action.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ACTION_H */
+
index 9ce23bf7bf3e2faf5e07f437fe7b60f3ff1cb9fe..aa641bf0a008354d324b07e522a9782bc7b308d4 100644 (file)
 
 #include "button.h"
 #include "container.h"
+#include "widget.h"
 #include <cx/allocator.h>
 #include <cx/buffer.h>
 #include <cx/json.h>
 #include "../common/context.h"
 #include "../common/object.h"
+#include "../common/action.h"
 
 void ui_button_set_icon_name(GtkWidget *button, const char *icon) {
     if(!icon) {
@@ -63,6 +65,7 @@ GtkWidget* ui_create_button(
         const char *tooltip,
         ui_callback onclick,
         void *userdata,
+        const char *action,
         int event_value,
         bool activate_event)
 {
@@ -72,12 +75,13 @@ GtkWidget* ui_create_button(
         gtk_widget_set_tooltip_text(button, tooltip);
     }
     
-    if(onclick) {
+    if(onclick || action) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
         event->userdata = userdata;
         event->callback = onclick;
         event->value = event_value;
+        event->action = action ? strdup(action) : NULL;
         event->customdata = NULL;
         event->customint = 0;
 
@@ -89,7 +93,7 @@ GtkWidget* ui_create_button(
         g_signal_connect(
                 button,
                 "destroy",
-                G_CALLBACK(ui_destroy_userdata),
+                G_CALLBACK(ui_destroy_eventdata),
                 event);
         if(activate_event) {
             g_signal_connect(
@@ -98,13 +102,21 @@ GtkWidget* ui_create_button(
                 G_CALLBACK(ui_button_clicked),
                 event);
         }
+        
+        if(action) {
+            uic_bind_action(obj->ctx, action, button, (ui_enablefunc)ui_set_enabled);
+            UiAction *ui_action = uic_resolve_action(obj->ctx, action);
+            if(!ui_action) {
+                ui_set_enabled(button, FALSE);
+            }
+        }
     }
     
     return button;
 }
 
 UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
-    GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, 0, FALSE);
+    GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, args->action, 0, FALSE);
     ui_set_name_and_style(button, args->name, args->style_class);
     ui_set_widget_states(obj->ctx, button, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
@@ -124,7 +136,13 @@ void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
     e.eventdatatype = 0;
     e.intval = event->value;
     e.set = ui_get_setop();
-    event->callback(&e, event->userdata);
+    if(event->callback) {
+        event->callback(&e, event->userdata);
+    }
+    
+    if(event->action) {
+        uic_action_callback(&e, event->action);
+    }
 }
 
 void ui_button_set_label(UIWIDGET button, const char *label) {
@@ -135,6 +153,47 @@ void ui_button_set_icon(UIWIDGET button, const char *icon) {
     ui_button_set_icon_name(button, icon);
 }
 
+void ui_button_set_tooltip(UIWIDGET button, const char *tooltip) {
+    gtk_widget_set_tooltip_text(GTK_WIDGET(button), tooltip);
+}
+
+void ui_togglebutton_set_label(UIWIDGET button, const char *label) {
+    ui_button_set_label(button, label);
+}
+
+void ui_togglebutton_set_icon(UIWIDGET button, const char *icon) {
+    ui_button_set_icon(button, icon);
+}
+
+void ui_togglebutton_set_tooltip(UIWIDGET button, const char *tooltip) {
+    ui_button_set_tooltip(button, tooltip);
+}
+
+void ui_checkbox_set_label(UIWIDGET button, const char *label) {
+    ui_button_set_label(button, label);
+}
+
+void ui_checkbox_set_icon(UIWIDGET button, const char *icon) {
+    ui_button_set_icon(button, icon);
+}
+
+void ui_checkbox_set_tooltip(UIWIDGET button, const char *tooltip) {
+    ui_button_set_tooltip(button, tooltip);
+}
+
+void ui_radiobutton_set_label(UIWIDGET button, const char *label) {
+    ui_button_set_label(button, label);
+}
+
+void ui_radiobutton_set_icon(UIWIDGET button, const char *icon) {
+    ui_button_set_icon(button, icon);
+}
+
+void ui_radiobutton_set_tooltip(UIWIDGET button, const char *tooltip) {
+    ui_button_set_tooltip(button, tooltip);
+}
+
+
 int64_t ui_toggle_button_get(UiInteger *integer) {
     GtkToggleButton *button = integer->obj;
     integer->value = (int)gtk_toggle_button_get_active(button);
@@ -170,7 +229,14 @@ static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
     e.eventdatatype = 0;
     e.intval = gtk_toggle_button_get_active(widget);
     e.set = ui_get_setop();
-    event->callback(&e, event->userdata);    
+    
+    if(event->callback) {
+        event->callback(&e, event->userdata);    
+    }
+    
+    if(event->action) {
+        uic_action_callback(&e, event->action);
+    }
 }
 
 static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) {
@@ -191,6 +257,7 @@ void ui_setup_togglebutton(
         UiInteger *value,
         ui_callback onchange,
         void *onchangedata,
+        const char *action,
         int enable_state)
 {
     if(label) {
@@ -201,6 +268,14 @@ void ui_setup_togglebutton(
         gtk_widget_set_tooltip_text(togglebutton, tooltip);
     }
     
+   if(action) {
+        uic_bind_action(obj->ctx, action, togglebutton, (ui_enablefunc)ui_set_enabled);
+        UiAction *ui_action = uic_resolve_action(obj->ctx, action);
+        if(!ui_action) {
+            ui_set_enabled(togglebutton, FALSE);
+        }
+    }
+    
     ui_bind_togglebutton(
             obj,
             togglebutton,
@@ -211,6 +286,7 @@ void ui_setup_togglebutton(
             (ui_toggled_func)ui_toggled_callback,
             onchange,
             onchangedata,
+            action,
             (ui_toggled_func)ui_togglebutton_enable_state_callback,
             enable_state
             );
@@ -226,6 +302,7 @@ void ui_bind_togglebutton(
         void (*toggled_callback)(void*, void*),
         ui_callback onchange,
         void *onchangedata,
+        const char *action,
         void (*enable_state_func)(void*, void*),
         int enable_state)
 {
@@ -257,11 +334,12 @@ void ui_bind_togglebutton(
                 event);
     }
     
-    if(onchange) {
+    if(onchange || action) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
         event->userdata = onchangedata;
         event->callback = onchange;
+        event->action = action ? strdup(action) : NULL,
         event->value = 0;
         event->customdata = NULL;
         event->customint = 0;
@@ -274,10 +352,10 @@ void ui_bind_togglebutton(
         g_signal_connect(
                 widget,
                 "destroy",
-                G_CALLBACK(ui_destroy_userdata),
+                G_CALLBACK(ui_destroy_eventdata),
                 event);
     }
-    
+     
     if(enable_state > 0) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
@@ -311,6 +389,7 @@ static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleAr
             args->value,
             args->onchange,
             args->onchangedata,
+            args->action,
             args->enable_state);
     ui_set_name_and_style(widget, args->name, args->style_class);
     ui_set_widget_states(obj->ctx, widget, args->states);
@@ -373,6 +452,7 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
             (ui_toggled_func)ui_checkbox_callback,
             args->onchange,
             args->onchangedata,
+            args->action,
             (ui_toggled_func)ui_checkbox_enable_state,
             args->enable_state);
     
@@ -497,6 +577,171 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
 
 #endif
 
+static void content_toggle_button_changed(UiContentToggleButton *button) {
+    if(button->toggled) {
+        gtk_button_set_label(GTK_BUTTON(button->widget), button->label1);
+        ui_button_set_icon_name(button->widget, button->icon1);
+        gtk_widget_set_tooltip_text(button->widget, button->tooltip1);
+    } else {
+        gtk_button_set_label(GTK_BUTTON(button->widget), button->label0);
+        ui_button_set_icon_name(button->widget, button->icon0);
+        gtk_widget_set_tooltip_text(button->widget, button->tooltip0);
+    }
+    
+    UiEvent e;
+    e.obj = button->obj;
+    e.window = button->obj->window;
+    e.document = button->obj->ctx->document;
+    e.eventdata = NULL;
+    e.eventdatatype = 0;
+    e.intval = button->toggled;
+    e.set = ui_get_setop();
+    
+    if(button->onchange) {
+        button->onchange(&e, button->onchangedata);    
+    }
+    
+    if(button->onchange_action) {
+        uic_action_callback(&e, button->onchange_action);
+    }
+}
+
+static void ui_content_toggle_button_toggled(GtkWidget *widget, UiContentToggleButton *button) {
+    button->toggled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+    if(ui_get_setop() == 0) {
+        content_toggle_button_changed(button);
+    }
+}
+
+static void ui_content_toggle_button_clicked(GtkWidget *widget, UiContentToggleButton *button) {
+    button->toggled = !button->toggled;
+    content_toggle_button_changed(button);
+}
+
+static void ui_destroy_content_togglebutton(GtkWidget *widget, UiContentToggleButton *button) {
+    free(button->label0);
+    free(button->icon0);
+    free(button->tooltip0);
+    free(button->label1);
+    free(button->icon1);
+    free(button->tooltip1);
+    free(button->onchange_action);
+    free(button);
+}
+
+static void ui_content_togglebutton_enabled_by_state(void *data, int enabled) {
+    UiContentToggleButton *button = data;
+    if(button->toggled != enabled) {
+        button->toggled = enabled;
+        content_toggle_button_changed(button);
+    }
+}
+
+UIWIDGET ui_create_content_togglebutton(UiObject *obj, UiContentToggleArgs *args) {
+    UiContentToggleButton *button = malloc(sizeof(UiContentToggleButton));
+    memset(button, 0, sizeof(UiContentToggleButton));
+    button->obj = obj;
+    button->label0 = args->label0 ? strdup(args->label0) : NULL;
+    button->icon0 = args->icon0 ? strdup(args->icon0) : NULL;
+    button->tooltip0 = args->tooltip0 ? strdup(args->tooltip0) : NULL;
+    button->label1 = args->label1 ? strdup(args->label1) : NULL;
+    button->icon1 = args->icon1 ? strdup(args->icon1) : NULL;
+    button->tooltip1 = args->tooltip1 ? strdup(args->tooltip1) : NULL;
+    button->enable_state = args->enable_state;
+    button->var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
+    button->onchange = args->onchange;
+    button->onchangedata = args->onchangedata;
+    button->onchange_action = args->action ? strdup(args->action) : NULL;
+    
+    const char *label = args->label0;
+    const char *icon = args->icon0;
+    const char *tooltip = args->tooltip0;
+    if(button->var) {
+        UiInteger *i = button->var->value;
+        i->obj = button;
+        i->get = ui_ctntogglebutton_get;
+        i->set = ui_ctntogglebutton_set;
+        
+        if(i->value) {
+            label = args->label1;
+            icon = args->label1;
+            tooltip = args->tooltip1;
+            button->toggled = 1;
+        }
+    }
+    
+    GtkWidget *widget;
+    if(args->istogglebutton) {
+        widget = gtk_toggle_button_new_with_label(label);
+        
+        g_signal_connect(
+                widget,
+                "toggled",
+                G_CALLBACK(ui_content_toggle_button_toggled),
+                button);
+    } else {
+        widget = gtk_button_new_with_label(label);
+        
+        g_signal_connect(
+                widget,
+                "clicked",
+                G_CALLBACK(ui_content_toggle_button_clicked),
+                button);
+    }
+    ui_button_set_icon_name(widget, icon);
+    gtk_widget_set_tooltip_text(widget, tooltip);
+    button->widget = widget;
+    
+    if(args->action) {
+        uic_bind_action(obj->ctx, args->action, widget, (ui_enablefunc)ui_set_enabled);
+        UiAction *ui_action = uic_resolve_action(obj->ctx, args->action);
+        if(!ui_action) {
+            ui_set_enabled(widget, FALSE);
+        }
+    }
+    
+    if(args->toggled_by_state != 0) {
+        CxList *ls = cxArrayListCreate(NULL, sizeof(int), 1);
+        cxListAdd(ls, &args->toggled_by_state);
+        uic_add_state_widget(obj->ctx, button, ui_content_togglebutton_enabled_by_state, ls);
+        cxListFree(ls);
+    }
+    
+    g_signal_connect(
+            widget,
+            "destroy",
+            G_CALLBACK(ui_destroy_content_togglebutton),
+            button);
+    
+    g_object_set_data(G_OBJECT(widget), "ui_content_togglebutton", button);
+    return widget;
+}
+
+UIWIDGET ui_content_togglebutton_create(UiObject *obj, UiContentToggleArgs *args) {
+    GtkWidget *widget = ui_create_content_togglebutton(obj, args);
+    
+    ui_set_name_and_style(widget, args->name, args->style_class);
+    ui_set_widget_states(obj->ctx, widget, args->states);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
+    uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states);
+    return widget;
+}
+
+int64_t ui_ctntogglebutton_get(UiInteger *value) {
+    UiContentToggleButton *button = value->obj;
+    value->value = button->toggled;
+    return value->value;
+}
+
+void ui_ctntogglebutton_set(UiInteger *value, int64_t i) {
+    UiContentToggleButton *button = value->obj;
+    button->toggled = i != 0;
+    value->value = button->toggled;
+    content_toggle_button_changed(button);
+}
+
 #if GTK_MAJOR_VERSION >= 4
 #define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label)
 #define RADIOBUTTON_SET_GROUP(button, group) 
@@ -841,16 +1086,7 @@ static void linkbutton_callback(GtkWidget *widget, UiLinkButton *data) {
 static void linkbutton_clicked(GtkWidget *widget, UiLinkButton *data) {
     linkbutton_callback(widget, data);
     if(data->link) {   
-#if GTK_CHECK_VERSION(4, 0, 0)
-        GtkUriLauncher *launcher = gtk_uri_launcher_new (data->link);
-        gtk_uri_launcher_launch (launcher, NULL, NULL, NULL, NULL);
-        g_object_unref (launcher);
-#elif GTK_CHECK_VERSION(3, 22, 0)
-        GError *error = NULL;
-        gtk_show_uri_on_window(NULL, data->link, GDK_CURRENT_TIME, &error);
-#elif
-        // TODO: call xdg-open
-#endif
+        ui_open_uri(data->link);
     }
 }
 
@@ -938,6 +1174,7 @@ void ui_linkbutton_set(UiString *s, const char *str) {
     if(s->value.free) {
         s->value.free(s->value.ptr);
     }
+    s->value.ptr = NULL;
 #if GTK_MAJOR_VERSION == 3
     UiLinkButton *data = s->obj;
     GtkWidget *child = gtk_bin_get_child(GTK_BIN(data->widget));
index ce94b90c7dc04259e087553a2a195d35a949f1b5..4972f35f9dde75615b8ccc65bfc6c5d81646afd2 100644 (file)
 extern "C" {
 #endif
     
+typedef struct UiContentToggleButton {
+    UiObject *obj;
+    UiVar *var;
+    GtkWidget *widget;
+    char *label0;
+    char *icon0;
+    char *tooltip0;
+    char *label1;
+    char *icon1;
+    char *tooltip1;
+    ui_callback onchange;
+    void *onchangedata;
+    char *onchange_action;
+    int toggled;
+    int enable_state;
+} UiContentToggleButton;
+    
 typedef struct UiLinkButton {
     UiObject *obj;
     GtkWidget *widget;
@@ -58,6 +75,7 @@ GtkWidget* ui_create_button(
         const char *tooltip,
         ui_callback onclick,
         void *userdata,
+        const char *action,
         int event_value,
         bool activate_event);
 
@@ -71,6 +89,7 @@ void ui_setup_togglebutton(
         UiInteger *value,
         ui_callback onchange,
         void *onchangedata,
+        const char *action,
         int enable_state);
 
 void ui_bind_togglebutton(
@@ -83,6 +102,7 @@ void ui_bind_togglebutton(
         void (*toggled_callback)(void*, void*),
         ui_callback onchange,
         void *onchangedata,
+        const char *action,
         void (*enable_state_func)(void*, void*),
         int enable_state);
     
@@ -98,9 +118,14 @@ UIWIDGET ui_radiobutton_var(UiObject *obj, char *label, UiVar *var);
 
 void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event);
 
+UIWIDGET ui_create_content_togglebutton(UiObject *obj, UiContentToggleArgs *args);
+
 int64_t ui_switch_get(UiInteger *value);
 void ui_switch_set(UiInteger *value, int64_t i);
 
+int64_t ui_ctntogglebutton_get(UiInteger *value);
+void ui_ctntogglebutton_set(UiInteger *value, int64_t i);
+
 int64_t ui_radiobutton_get(UiInteger *value);
 void ui_radiobutton_set(UiInteger *value, int64_t i);
 
index 5489ecbdc232f26da8d95e670ded6299332c3248..30960ffb5f0490793f954b5b1e800a0d7d58f29b 100644 (file)
 
 
 void ui_container_begin_close(UiObject *obj) {
-    UiContainerX *ct = obj->container_end;
+    UiContainer *ct = obj->container_end;
     ct->close = 1;
 }
 
 int ui_container_finish(UiObject *obj) {
-    UiContainerX *ct = obj->container_end;
+    UiContainer *ct = obj->container_end;
     if(ct->close) {
         ui_end_new(obj);
         return 0;
@@ -82,7 +82,7 @@ GtkWidget* ui_subcontainer_create(
 {
     GtkWidget *sub = NULL;
     GtkWidget *add = NULL;
-    UiContainerX *container = NULL;
+    UiContainer *container = NULL;
     switch(type) {
         default: {
             sub = ui_gtk_vbox_new(spacing);
@@ -125,11 +125,11 @@ void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_fun
     container->container.widget = widget;
     container->add = add_child;
     container->userdata = userdata;
-    uic_object_push_container(obj, (UiContainerX*)container);
+    uic_object_push_container(obj, (UiContainer*)container);
 }
 
 /* -------------------- Box Container -------------------- */
-UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
+UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
     UiBoxContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
@@ -137,7 +137,7 @@ UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType
     ct->container.widget = box;
     ct->container.add = ui_box_container_add;
     ct->type = type;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -172,7 +172,7 @@ void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *l
 #endif
 }
 
-UiContainerX* ui_grid_container(
+UiContainer* ui_grid_container(
         UiObject *obj,
         GtkWidget *grid,
         UiBool def_hexpand,
@@ -192,7 +192,7 @@ UiContainerX* ui_grid_container(
     ct->container.add = ui_grid_container_add;
     UI_GTK_V2(ct->width = 0);
     UI_GTK_V2(ct->height = 1);
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 
@@ -271,14 +271,14 @@ void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget) {
 }
 #endif
 
-UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame) {
+UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
     UiContainerPrivate *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiContainerPrivate));
     ct->widget = frame;
     ct->add = ui_frame_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -286,14 +286,14 @@ void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout
     FRAME_SET_CHILD(ct->widget, widget);
 }
 
-UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander) {
+UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) {
     UiContainerPrivate *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiContainerPrivate));
     ct->widget = expander;
     ct->add = ui_expander_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -307,24 +307,24 @@ void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget,
     SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
 }
 
-UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
+UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
     UiContainerPrivate *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiContainerPrivate));
     ct->widget = scrolledwindow;
     ct->add = ui_scrolledwindow_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
-UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
+UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
     UiTabViewContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiTabViewContainer));
     ct->container.widget = tabview;
     ct->container.add = ui_tabview_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -390,7 +390,7 @@ UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType
     ui_set_name_and_style(box, args->name, args->style_class);
     ct->add(ct, box, &layout);
     
-    UiContainerX *container = ui_box_container(obj, box, type);
+    UiContainer *container = ui_box_container(obj, box, type);
     uic_object_push_container(obj, container);
     
     uic_widget_set_visibility_states(obj->ctx, box, args->visibility_states);
@@ -428,7 +428,7 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
     ui_set_name_and_style(grid, args->name, args->style_class);
     ct->add(ct, grid, &layout);
     
-    UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
+    UiContainer *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
     uic_object_push_container(obj, container);
     
     uic_widget_set_visibility_states(obj->ctx, grid, args->visibility_states);
@@ -476,7 +476,7 @@ UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
     if(sub) {
         FRAME_SET_CHILD(frame, sub);
     } else {
-        UiContainerX *container = ui_frame_container(obj, frame);
+        UiContainer *container = ui_frame_container(obj, frame);
         uic_object_push_container(obj, container);
     }
     
@@ -502,7 +502,7 @@ UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
     if(sub) {
         EXPANDER_SET_CHILD(expander, sub);
     } else {
-        UiContainerX *container = ui_expander_container(obj, expander);
+        UiContainer *container = ui_expander_container(obj, expander);
         uic_object_push_container(obj, container);
     }
     
@@ -529,7 +529,7 @@ UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
     if(sub) {
         SCROLLEDWINDOW_SET_CHILD(sw, sub);
     } else {
-        UiContainerX *container = ui_scrolledwindow_container(obj, sw);
+        UiContainer *container = ui_scrolledwindow_container(obj, sw);
         uic_object_push_container(obj, container);
     }
     
@@ -821,7 +821,7 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, widget, &layout);
     
-    UiContainerX *container = ui_tabview_container(obj, widget);
+    UiContainer *container = ui_tabview_container(obj, widget);
     uic_object_push_container(obj, container);
     
     uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states);
@@ -830,7 +830,7 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
 }
 
 static GtkWidget* create_tab(UiObject *obj, UiGtkTabView *tabview, const char *title, int tab) {
-    UiContainerX *container;
+    UiContainer *container;
     GtkWidget *sub;
     switch(tabview->subcontainer) {
         default: {
@@ -916,7 +916,7 @@ static void hb_set_part(UiObject *obj, int part) {
             sizeof(UiHeaderbarContainer));
     memcpy(hb, ct, sizeof(UiHeaderbarContainer));
     hb->part = part;
-    uic_object_push_container(obj, (UiContainerX*)hb);
+    uic_object_push_container(obj, (UiContainer*)hb);
 }
 
 void ui_headerbar_start_create(UiObject *obj) {
@@ -939,7 +939,7 @@ UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) {
     ui_set_name_and_style(box, args->name, args->style_class);
     ct->add(ct, box, &layout);
     
-    UiContainerX *container = ui_headerbar_fallback_container(obj, box);
+    UiContainer *container = ui_headerbar_fallback_container(obj, box);
     uic_object_push_container(obj, container);
     
     return box;
@@ -949,21 +949,21 @@ static void hb_fallback_set_part(UiObject *obj, int part) {
      UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     GtkWidget *headerbar = ct->widget;
     
-    UiContainerX *container = ui_headerbar_container(obj, headerbar);
+    UiContainer *container = ui_headerbar_container(obj, headerbar);
     uic_object_push_container(obj, container);
     
     UiHeaderbarContainer *hb = (UiHeaderbarContainer*)container;
     hb->part = part;
 }
 
-UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
     UiHeaderbarContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiHeaderbarContainer));
     ct->container.widget = headerbar;
     ct->container.add = ui_headerbar_fallback_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -979,20 +979,20 @@ UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
         return ui_headerbar_fallback_create(obj, args);
     }
     
-    UiContainerX *container = ui_headerbar_container(obj, headerbar);
+    UiContainer *container = ui_headerbar_container(obj, headerbar);
     uic_object_push_container(obj, container);
     
     return headerbar;    
 }
 
-UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
     UiHeaderbarContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiHeaderbarContainer));
     ct->container.widget = headerbar;
     ct->container.add = ui_headerbar_container_add;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
@@ -1035,7 +1035,7 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
     ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
     adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
     
-    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
     uic_object_push_container(obj, container);
     
     return box;
@@ -1048,7 +1048,7 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
     ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
     BOX_ADD_EXPAND(sidebar_vbox, box);
     
-    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
     uic_object_push_container(obj, container);
     
     return box;
@@ -1068,7 +1068,7 @@ static UIWIDGET splitwindow_panel(UiObject *obj, GtkWidget *pbox, UiSidebarArgs
     ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
     BOX_ADD_EXPAND(pbox, box);
     
-    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
     uic_object_push_container(obj, container);
     
     return box;
@@ -1135,7 +1135,7 @@ static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSpl
     }
     
     UiSplitPane *splitpane = ui_create_splitpane_data(pane0, orientation, max, args->initial_position);
-    UiContainerX *container = ui_splitpane_container(obj, pane0, splitpane);
+    UiContainer *container = ui_splitpane_container(obj, pane0, splitpane);
     uic_object_push_container(obj, container);
     
     g_object_set_data(G_OBJECT(pane0), "ui_splitpane", splitpane);
@@ -1172,12 +1172,12 @@ UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation
     return ct;
 }
 
-UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) {
+UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) {
     UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer));
     ct->container.widget = pane;
     ct->container.add = ui_splitpane_container_add;
     ct->splitpane = data;
-    return (UiContainerX*)ct;
+    return (UiContainer*)ct;
 }
 
 void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
index a5e46b2febf605ee407484900fb7342def5f0bfb..352b50ea01cf6f729eea6aeb96a2f87b8dfe07e2 100644 (file)
@@ -50,7 +50,7 @@ typedef struct UiDocumentView UiDocumentView;
 
 typedef struct UiContainerPrivate UiContainerPrivate;
 struct UiContainerPrivate {
-    UiContainerX container;
+    UiContainer container;
     GtkWidget *widget;
     UIMENU menu;
     
@@ -160,11 +160,11 @@ GtkWidget* ui_subcontainer_create(
 GtkWidget* ui_gtk_set_margin(GtkWidget *widget, int margin, int margin_left, int margin_right, int margin_top, int margin_bottom);
 UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type);
 
-UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
+UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
 void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing);
-UiContainerX* ui_grid_container(
+UiContainer* ui_grid_container(
         UiObject *obj,
         GtkWidget *grid,
         UiBool def_hexpand,
@@ -173,20 +173,20 @@ UiContainerX* ui_grid_container(
         UiBool def_vfill);
 void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame);
+UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
 void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander);
+UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander);
 void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
+UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
 void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
+UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
 void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init);
-UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data);
+UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data);
 void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 int64_t ui_splitpane_get(UiInteger *i);
@@ -197,11 +197,11 @@ UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview);
 void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab);
 
 #if GTK_CHECK_VERSION(3, 10, 0)
-UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
+UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
 void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 #endif
 
-UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
+UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
 void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 #ifdef __cplusplus
index ef1d9c7e151fa79cf0203d2906eb32dab19031b0..a8ba5356908836fcf80ad9d986eddab2b6a0863d 100644 (file)
@@ -30,6 +30,9 @@
 
 #include "button.h"
 #include "menu.h"
+#include "../ui/widget.h"
+
+#include <cx/array_list.h>
 
 #include "../ui/properties.h"
 
@@ -66,53 +69,66 @@ void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *m
     }
     
     // main toolbar
-    ui_headerbar_add_items(obj, main_headerbar, left_defaults, UI_TOOLBAR_LEFT);
-    ui_headerbar_add_items(obj, main_headerbar, center_defaults, UI_TOOLBAR_CENTER);
+    ui_headerbar_add_items(obj, main_headerbar, left_defaults, UI_TOOLBAR_LEFT, NULL);
+    ui_headerbar_add_items(obj, main_headerbar, center_defaults, UI_TOOLBAR_CENTER, NULL);
     
     if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHT) {
         ui_add_headerbar_menu(main_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
     }
-    ui_headerbar_add_items(obj, main_headerbar, right_defaults, UI_TOOLBAR_RIGHT);
+    ui_headerbar_add_items(obj, main_headerbar, right_defaults, UI_TOOLBAR_RIGHT, NULL);
     
     // sidebar
     if(sidebar_headerbar) {
         // ui_headerbar_add_items pos parameter uses only UI_TOOLBAR_LEFT, UI_TOOLBAR_CENTER, UI_TOOLBAR_RIGHT
-        ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_left_defaults, UI_TOOLBAR_LEFT);
+        ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_left_defaults, UI_TOOLBAR_LEFT, NULL);
 
         if(appmenu && appmenu_pos == UI_TOOLBAR_SIDEBAR_RIGHT) {
             ui_add_headerbar_menu(sidebar_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
         }
-        ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_right_defaults, UI_TOOLBAR_RIGHT);
+        ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_right_defaults, UI_TOOLBAR_RIGHT, NULL);
     }
     
     // right panel
     if(right_headerbar) {
-        ui_headerbar_add_items(obj, right_headerbar, rightpanel_left_defaults, UI_TOOLBAR_LEFT);
-        ui_headerbar_add_items(obj, right_headerbar, rightpanel_center_defaults, UI_TOOLBAR_CENTER);
+        // also add central toolbar items, in case the central pane is hidden
+        CxList *backup_toolbar_widgets = cxArrayListCreate(obj->ctx->allocator, CX_STORE_POINTERS, 16);
+        ui_headerbar_add_items(obj, right_headerbar, left_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets);
+        ui_headerbar_add_items(obj, right_headerbar, center_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets);
+        ui_headerbar_add_items(obj, right_headerbar, right_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets);
+        CxIterator i = cxListIterator(backup_toolbar_widgets);
+        cx_foreach(GtkWidget *, w, i) {
+            ui_set_visible(w, FALSE);
+        }
+        g_object_set_data(G_OBJECT(obj->widget), "ui_toolbar_center_backup", backup_toolbar_widgets);
+        
+        // main items for the right panel
+        ui_headerbar_add_items(obj, right_headerbar, rightpanel_left_defaults, UI_TOOLBAR_LEFT, NULL);
+        ui_headerbar_add_items(obj, right_headerbar, rightpanel_center_defaults, UI_TOOLBAR_CENTER, NULL);
 
         if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHTPANEL_RIGHT) {
             ui_add_headerbar_menu(right_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
         }
-        ui_headerbar_add_items(obj, right_headerbar, rightpanel_right_defaults, UI_TOOLBAR_RIGHT);
+        ui_headerbar_add_items(obj, right_headerbar, rightpanel_right_defaults, UI_TOOLBAR_RIGHT, NULL);
     }
 }
 
-static void create_item(UiObject *obj, GtkWidget *headerbar, GtkWidget *box, UiToolbarItemI *i, enum UiToolbarPos pos) {
+static GtkWidget* create_item(UiObject *obj, GtkWidget *headerbar, GtkWidget *box, UiToolbarItemI *i, enum UiToolbarPos pos) {
     switch(i->type) {
         case UI_TOOLBAR_ITEM: {
-            ui_add_headerbar_item(headerbar, box, (UiToolbarItem*)i, obj, pos);
-            break;
+            return ui_add_headerbar_item(headerbar, box, (UiToolbarItem*)i, obj, pos);
         }
         case UI_TOOLBAR_TOGGLEITEM: {
-            ui_add_headerbar_toggleitem(headerbar, box, (UiToolbarToggleItem*)i, obj, pos);
-            break;
+            return ui_add_headerbar_toggleitem(headerbar, box, (UiToolbarToggleItem*)i, obj, pos);
+        }
+        case UI_TOOLBAR_CONTENT_TOGGLEITEM: {
+            return ui_add_headerbar_content_toggleitem(headerbar, box, (UiToolbarContentToggleItem*)i, obj, pos);
         }
         case UI_TOOLBAR_MENU: {
-            ui_add_headerbar_menu(headerbar, box, (UiToolbarMenuItem*)i, obj, pos);
-            break;
+            return ui_add_headerbar_menu(headerbar, box, (UiToolbarMenuItem*)i, obj, pos);
         }
         default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type);
     }
+    return NULL;
 }
 
 static void headerbar_add(GtkWidget *headerbar, GtkWidget *box, GtkWidget *item, enum UiToolbarPos pos) {
@@ -137,12 +153,15 @@ static void headerbar_add(GtkWidget *headerbar, GtkWidget *box, GtkWidget *item,
     }
 }
 
-void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos) {
+void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos, CxList *out_items) {
     GtkWidget *box = NULL;
     
     if(pos == UI_TOOLBAR_CENTER && cxListSize(items) > 0) {
         box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
         UI_HEADERBAR_SET_TITLE_WIDGET(headerbar, box);
+        if(out_items) {
+            cxListAdd(out_items, box);
+        }
     }
     
     CxIterator i = pos == UI_TOOLBAR_RIGHT ? cxListBackwardsIterator(items) : cxListIterator(items);
@@ -152,25 +171,29 @@ void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items,
             fprintf(stderr, "unknown toolbar item: %s\n", def);
             continue;
         }
-        create_item(obj, headerbar, box, item, pos);
+        GtkWidget *item_widget = create_item(obj, headerbar, box, item, pos);
+        if(out_items && !box) {
+            cxListAdd(out_items, item_widget);
+        }
     }
 }
 
-void ui_add_headerbar_item(
+GtkWidget* ui_add_headerbar_item(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarItem *item,
         UiObject *obj,
         enum UiToolbarPos pos)
 {
-    GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, 0, FALSE);
+    GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, item->args.action, 0, FALSE);
     ui_set_widget_states(obj->ctx, button, item->args.states);
     ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
     WIDGET_ADD_CSS_CLASS(button, "flat");
     headerbar_add(headerbar, box, button, pos);
+    return button;
 }
 
-void ui_add_headerbar_toggleitem(
+GtkWidget* ui_add_headerbar_toggleitem(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarToggleItem *item,
@@ -181,11 +204,39 @@ void ui_add_headerbar_toggleitem(
     ui_set_widget_states(obj->ctx, button, item->args.states);
     ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
     WIDGET_ADD_CSS_CLASS(button, "flat");
-    ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, 0);
+    ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, item->args.action, 0);
     headerbar_add(headerbar, box, button, pos);
+    return button;
 }
 
-void ui_add_headerbar_menu(
+GtkWidget* ui_add_headerbar_content_toggleitem(
+        GtkWidget *headerbar,
+        GtkWidget *box,
+        UiToolbarContentToggleItem *item,
+        UiObject *obj,
+        enum UiToolbarPos pos)
+{
+    UiContentToggleArgs args = { 0 };
+    args.label0 = item->args.label0;
+    args.icon0 = item->args.icon0;
+    args.tooltip0 = item->args.tooltip0;
+    args.label1 = item->args.label1;
+    args.icon1 = item->args.icon1;
+    args.tooltip1 = item->args.tooltip1;
+    args.varname = item->args.varname;
+    args.onchange = item->args.onchange;
+    args.onchangedata = item->args.onchangedata;
+    args.action = item->args.action;
+    args.istogglebutton = item->args.istogglebutton;
+    args.toggled_by_state = item->args.toggled_by_state;
+    
+    GtkWidget *button = ui_create_content_togglebutton(obj, &args);
+    WIDGET_ADD_CSS_CLASS(button, "flat");
+    headerbar_add(headerbar, box, button, pos);
+    return button;
+}
+
+GtkWidget* ui_add_headerbar_menu(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarMenuItem *item,
@@ -222,6 +273,8 @@ void ui_add_headerbar_menu(
 #endif
     
     headerbar_add(headerbar, box, menubutton, pos);
+    
+    return menubutton;
 }
     
 #endif // GTK_CHECK_VERSION(3, 10, 0)
index d3786c8cd15972664980a1eff2c84acc84d7b6c0..50e877b15409e9871200c633bf753e2ac57a1e55 100644 (file)
@@ -65,23 +65,30 @@ extern "C" {
     
 void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *main_headerbar, GtkWidget *right_headerbar);
 
-void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos);
+void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos, CxList *out_items);
 
-void ui_add_headerbar_item(
+GtkWidget* ui_add_headerbar_item(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarItem *item,
         UiObject *obj,
         enum UiToolbarPos pos);
 
-void ui_add_headerbar_toggleitem(
+GtkWidget* ui_add_headerbar_toggleitem(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarToggleItem *item,
         UiObject *obj,
         enum UiToolbarPos pos);
 
-void ui_add_headerbar_menu(
+GtkWidget* ui_add_headerbar_content_toggleitem(
+        GtkWidget *headerbar,
+        GtkWidget *box,
+        UiToolbarContentToggleItem *item,
+        UiObject *obj,
+        enum UiToolbarPos pos);
+
+GtkWidget* ui_add_headerbar_menu(
         GtkWidget *headerbar,
         GtkWidget *box,
         UiToolbarMenuItem *item,
index 16568eed5028fc013aa6f8c1b9287c60a1d740b1..1dfd52fcaa62b27c296683b088b9b3c0f7474bdb 100644 (file)
@@ -123,6 +123,8 @@ UiIcon* ui_fileicon(size_t size) {
     char *path = g_file_get_path(file);
     if(!path) {
         icon = ui_icon("application-x-generic", size);
+    } else {
+        g_free(path);
     }
 #else
     if(!icon) {
@@ -143,6 +145,7 @@ GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) {
         GError *error = NULL;
         char *path = g_file_get_path(file);
         icon->pixbuf = gdk_pixbuf_new_from_file(path, &error);
+        g_free(path);
     }
     return icon->pixbuf;
 }
index f3a3895465a342f3360858ab4a9a30ec1ae5e4ae..14f8aecf3fafab57ec6b360c9013eceb804c8bad 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "../common/context.h"
 #include "../common/object.h"
+#include "../common/action.h"
 #include "container.h"
 
 #include <cx/array_list.h>
@@ -83,14 +84,19 @@ static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
     tableview->multiselection = args->multiselection;
     tableview->onactivate = args->onactivate;
     tableview->onactivatedata = args->onactivatedata;
+    tableview->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
     tableview->onselection = args->onselection;
     tableview->onselectiondata = args->onselectiondata;
+    tableview->onselection_action = args->onselection_action ? strdup(args->onselection_action) : NULL;
     tableview->ondragstart = args->ondragstart;
     tableview->ondragstartdata = args->ondragstartdata;
+    tableview->ondragstart_action = args->ondragstart_action ? strdup(args->ondragstart_action) : NULL;
     tableview->ondragcomplete = args->ondragcomplete;
     tableview->ondragcompletedata = args->ondragcompletedata;
+    tableview->ondragcomplete_action = args->ondragcomplete_action ? strdup(args->ondragcomplete_action) : NULL;
     tableview->ondrop = args->ondrop;
     tableview->ondropdata = args->ondropdata;
+    tableview->ondrop_action = args->ondrop_action ? strdup(args->ondrop_action) : NULL;
     tableview->selection.count = 0;
     tableview->selection.rows = NULL;
     tableview->current_row = -1;
@@ -254,7 +260,7 @@ static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item,
     } else if(type == UI_BOOL_EDITABLE) {
         GtkWidget *checkbox = gtk_check_button_new();
         gtk_list_item_set_child(item, checkbox);
-    }else {
+    } else {
         GtkWidget *label = gtk_label_new(NULL);
         gtk_label_set_xalign(GTK_LABEL(label), 0);
         gtk_list_item_set_child(item, label);
@@ -345,6 +351,7 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
         }
         case UI_STRING: {
             gtk_label_set_label(GTK_LABEL(child), data);
+            gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_END);
             if(freevalue) {
                 free(data);
             }
@@ -508,7 +515,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     }
     
     // event handling
-    if(args->onactivate) {
+    if(args->onactivate || args->onactivate_action) {
         // columnview and listview can use the same callback function, because
         // the first parameter (which is technically a different pointer type)
         // is ignored
@@ -718,7 +725,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     }
     
     // event handling
-    if(args->onactivate) {
+    if(args->onactivate || args->onactivate_action) {
         g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
     }
     if(args->contextmenu) {
@@ -806,7 +813,7 @@ static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
     return sel;
 }
 
-static void listview_event(ui_callback cb, void *cbdata, UiListView *view) {
+static void listview_event(ui_callback cb, void *cbdata, const char *action, UiListView *view) {
     UiEvent event;
     event.obj = view->obj;
     event.document = event.obj->ctx->document;
@@ -818,6 +825,10 @@ static void listview_event(ui_callback cb, void *cbdata, UiListView *view) {
     if(cb) {
         cb(&event, cbdata);
     }
+    
+    if(action) {
+        uic_action_callback(&event, action);
+    }
 }
 
 static void listview_update_selection(UiListView *view) {
@@ -868,14 +879,14 @@ void ui_columnview_activate(void *ignore, guint position, gpointer userdata) {
     if(view->selection.count == 0) {
         listview_update_selection(view);
     }
-    listview_event(view->onactivate, view->onactivatedata, view);
+    listview_event(view->onactivate, view->onactivatedata, view->onactivate_action, view);
 }
 
 void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) {
     UiListView *view = userdata;
     listview_update_selection(view);
     if(ui_selection_events_is_enabled()) {
-        listview_event(view->onselection, view->onselectiondata, view);
+        listview_event(view->onselection, view->onselectiondata, view->onselection_action, view);
     }
 }
 
@@ -927,6 +938,9 @@ void ui_listview_update2(UiList *list, int i) {
     if(i < 0) {
         cxMapClear(view->bound_rows);
         ui_update_liststore(view->liststore, list);
+        free(view->selection.rows);
+        view->selection.rows = NULL;
+        view->selection.count = 0;
     } else {
         void *value = list->get(list, i);
         if(value) {
@@ -1245,6 +1259,11 @@ static GtkListStore* create_list_store(UiListView *listview, UiList *list) {
     return store;
 }
 
+static void ui_destroy_tree_eventdata(GtkWidget *object, UiTreeEventData *data) {
+    free(data->activate_action);
+    free(data->selection_action);
+    free(data);
+}
 
 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     // create treeview
@@ -1302,22 +1321,23 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     event->obj = obj;
     event->activate = args->onactivate;
     event->activatedata = args->onactivatedata;
+    event->activate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
     event->selection = args->onselection;
     event->selectiondata = args->onselectiondata;
+    event->selection_action = args->onselection_action ? strdup(args->onselection_action) : NULL;
     g_signal_connect(
             view,
             "destroy",
-            G_CALLBACK(ui_destroy_userdata),
+            G_CALLBACK(ui_destroy_tree_eventdata),
             event);
-    
-    if(args->onactivate) {
+    if(args->onactivate || args->onactivate_action) {
         g_signal_connect(
                 view,
                 "row-activated",
                 G_CALLBACK(ui_listview_activate_event),
                 event);
     }
-    if(args->onselection) {
+    if(args->onselection || args->onselection_action) {
         GtkTreeSelection *selection = gtk_tree_view_get_selection(
                 GTK_TREE_VIEW(view));
         g_signal_connect(
@@ -1529,20 +1549,27 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     list->obj = tableview;
     
     // add callback
-    UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
+    UiTreeEventData *event = malloc(sizeof(UiTreeEventData));
     event->obj = obj;
     event->activate = args->onactivate;
-    event->selection = args->onselection;
     event->activatedata = args->onactivatedata;
+    event->activate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
+    event->selection = args->onselection;
     event->selectiondata = args->onselectiondata;
-    if(args->onactivate) {
+    event->selection_action = args->onselection_action ? strdup(args->onselection_action) : NULL;
+    g_signal_connect(
+            view,
+            "destroy",
+            G_CALLBACK(ui_destroy_tree_eventdata),
+            event);
+    if(args->onactivate || args->onactivate_action) {
         g_signal_connect(
                 view,
                 "row-activated",
                 G_CALLBACK(ui_listview_activate_event),
                 event);
     }
-    if(args->onselection) {
+    if(args->onselection || args->onselection_action) {
         GtkTreeSelection *selection = gtk_tree_view_get_selection(
                 GTK_TREE_VIEW(view));
         g_signal_connect(
@@ -1551,8 +1578,6 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
                 G_CALLBACK(ui_listview_selection_event),
                 event);
     }
-    // TODO: destroy callback
-    
     
     if(args->ondragstart) {
         ui_listview_add_dnd(tableview, args);
@@ -1784,13 +1809,18 @@ void ui_listview_activate_event(
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = &selection;
+    e.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
     e.intval = selection.count > 0 ? selection.rows[0] : -1;
     e.set = ui_get_setop();
-    event->activate(&e, event->activatedata);
     
-    if(selection.count > 0) {
-        free(selection.rows);
+    if(event->activate) {
+        event->activate(&e, event->activatedata);
     }
+    if(event->activate_action) {
+        uic_action_callback(&e, event->activate_action);
+    }
+    
+    free(selection.rows);
 }
 
 void ui_listview_selection_event(
@@ -1808,13 +1838,17 @@ void ui_listview_selection_event(
     e.window = event->obj->window;
     e.document = event->obj->ctx->document;
     e.eventdata = &selection;
+    e.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
     e.intval = selection.count > 0 ? selection.rows[0] : -1;
     e.set = ui_get_setop();
-    event->selection(&e, event->selectiondata);
-    
-    if(selection.count > 0) {
-        free(selection.rows);
+    if(event->selection) {
+        event->selection(&e, event->selectiondata);
+    }
+    if(event->selection_action) {
+        uic_action_callback(&e, event->selection_action);
     }
+    
+    free(selection.rows);
 }
 
 UiListSelection ui_listview_get_selection(
@@ -2171,6 +2205,11 @@ void ui_table_dragdest_a(UIWIDGET tablewidget, int actions, char **targets, int
 */
 
 void ui_listview_destroy(GtkWidget *w, UiListView *v) {
+    free(v->onactivate_action);
+    free(v->onselection_action);
+    free(v->ondragstart_action);
+    free(v->ondragcomplete_action);
+    free(v->ondrop_action);
     //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL);
     if(v->var) {
         ui_destroy_boundvar(v->obj->ctx, v->var);
index e7beb0e79e2861bbcef9e316b04513a3b6b7baec..69f30e4d8f2c2d379e09dcc73cf25a22f754f42d 100644 (file)
@@ -81,14 +81,19 @@ struct UiListView {
 #endif
     ui_callback       onactivate;
     void              *onactivatedata;
+    char              *onactivate_action;
     ui_callback       onselection;
     void              *onselectiondata;
+    char              *onselection_action;
     ui_callback       ondragstart;
     void              *ondragstartdata;
+    char              *ondragstart_action;
     ui_callback       ondragcomplete;
     void              *ondragcompletedata;
+    char              *ondragcomplete_action;
     ui_callback       ondrop;
     void              *ondropdata;
+    char              *ondrop_action;
     ui_list_savefunc  onsave;
     void              *onsavedata;
     UiListSelection   selection;
@@ -101,6 +106,8 @@ typedef struct UiTreeEventData {
     ui_callback selection;
     void        *activatedata;
     void        *selectiondata;
+    char        *activate_action;
+    char        *selection_action;
 } UiTreeEventData;
 
 typedef struct UiListBox UiListBox;
index 8bfbbbfe493608bc5617ea9741f9dbff59be66c9..5ce909d057c9dfb12ea6348cbf434b80787f68c7 100644 (file)
@@ -37,6 +37,7 @@
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/types.h"
+#include "../common/action.h"
 #include "../ui/properties.h"
 #include "../ui/window.h"
 #include "container.h"
@@ -276,6 +277,7 @@ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObje
     ls->index = index;
     ls->oldcount = 0;
     ls->getvalue = il->getvalue;
+    ls->getvaluedata = il->getvaluedata;
     
     UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
     //UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
@@ -339,10 +341,13 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) {
         gtk_widget_show(widget);
     }
     
-    ui_getvaluefunc getvalue = list->getvalue;
+    ui_getvaluefunc2 getvalue = list->getvalue;
+    void *getvaluedata = list->getvaluedata;
     int i = 1;
+    int row = 0;
     while(elm) {
-        char *label = (char*) (getvalue ? getvalue(elm, 0) : elm);
+        UiBool freeResult = FALSE;
+        char *label = (char*) (getvalue ? getvalue(ls, elm, row, 0, getvaluedata, &freeResult) : elm);
         
         GtkWidget *widget = gtk_menu_item_new_with_label(label);
         gtk_menu_shell_insert(list->menu, widget, list->index + i);
@@ -371,6 +376,11 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) {
         
         elm = ui_list_next(ls);
         i++;
+        row++;
+        
+        if(freeResult) {
+            free(label);
+        }
     }
     
     list->oldcount = i;
@@ -590,7 +600,15 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         cxListFree(groups);
     }
     
-    if(i->callback != NULL) {
+    if(i->action) {
+        uic_bind_action(obj->ctx, i->action, action, (ui_enablefunc)action_enable);
+        UiAction *ui_action = uic_resolve_action(obj->ctx, i->action);
+        if(!ui_action) {
+            action_enable(action, FALSE);
+        }
+    }
+     
+    if(i->callback != NULL || i->action) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
         event->userdata = i->userdata;
@@ -598,6 +616,7 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         event->value = 0;
         event->customdata = NULL;
         event->customint = 0;
+        event->action = i->action ? strdup(i->action) : NULL;
 
         g_signal_connect(
                 action,
@@ -607,13 +626,13 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         g_signal_connect(
                 obj->widget,
                 "destroy",
-                G_CALLBACK(ui_destroy_userdata),
+                G_CALLBACK(ui_destroy_eventdata),
                 event);
     }
     
     char action_name[32];
     snprintf(action_name, 32, "win.%s", item->id);
-    
+     
     g_menu_append(parent, i->label, action_name);
 }
 
@@ -658,7 +677,7 @@ static void stateful_action_notify_group(UiMenuRadioGroup *group, UiInteger *i)
     
     CxIterator iter = cxListIterator(group->callbacks);
     cx_foreach(UiCallbackData *, cb, iter) {
-        event.intval = intval == iter.index;
+        event.intval = intval-1 == iter.index;
         if(cb->callback) {
             cb->callback(&event, cb->userdata);
         }
@@ -782,7 +801,7 @@ void ui_gmenu_add_radioitem(GMenu *parent, int index, UiMenuItemI *item, UiObjec
     cxListAdd(group->callbacks, &cb);
     
     
-    cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index);
+    cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index+1);
     g_menu_append(parent, i->label, action_name.ptr);
     free(action_name.ptr);
 }
@@ -815,6 +834,7 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject
     ls->index = index;
     ls->oldcount = 0;
     ls->getvalue = il->getvalue;
+    ls->getvaluedata = il->getvalue;
     
     GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
     g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
@@ -888,7 +908,12 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent
         evt.eventdatatype = uic_get_tmp_eventdata_type();
     }
     evt.intval = intval;
-    event->callback(&evt, event->userdata);
+    if(event->callback) {
+        event->callback(&evt, event->userdata);
+    }
+    if(event->action) {
+        uic_action_callback(&evt, event->action);
+    }
     uic_set_tmp_eventdata(NULL, 0);
 }
 
@@ -928,11 +953,13 @@ void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) {
     UiList *ls = list->var->value;
     
     // add list items
-    ui_getvaluefunc getvalue = list->getvalue;
+    ui_getvaluefunc2 getvalue = list->getvalue;
+    void *getvaluedata = list->getvaluedata;
     int i = 0;
     void* elm = ui_list_first(ls);
     while(elm) {
-        char *label = (char*) (getvalue ? getvalue(elm, 0) : elm);
+        UiBool freeResult = FALSE;
+        char *label = (char*) (getvalue ? getvalue(ls, elm, i, 0, getvaluedata, &freeResult) : elm);
         
         GMenuItem *item = g_menu_item_new(label, NULL);
         GVariant *v = g_variant_new("i", i);
@@ -942,6 +969,10 @@ void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) {
         
         elm = ui_list_next(ls);
         i++;
+        
+        if(freeResult) {
+            free(label);
+        }
     }
     
     list->oldcount = i;
index 4cfa419d81e176d30f12b3612d1767043165e95a..d113f336f1b193a317aa27cef715803b583004c3 100644 (file)
@@ -56,7 +56,8 @@ struct UiActiveMenuItemList {
     int              index;
     int              oldcount;
     UiVar            *var;
-    ui_getvaluefunc  getvalue;
+    ui_getvaluefunc2 getvalue;
+    void             *getvaluedata;
     ui_callback      callback;
     void             *userdata;
 };
@@ -95,7 +96,8 @@ struct UiActiveGMenuItemList {
     int              index;
     int              oldcount;
     UiVar            *var;
-    ui_getvaluefunc  getvalue;
+    ui_getvaluefunc2 getvalue;
+    void             *getvaluedata;
     ui_callback      callback;
     void             *userdata;
 };
index abad5a0679c8ab7a816f25b1260ab08ae5bbcffe..1c7964601c6637a9839c0348835efc036886e885 100644 (file)
@@ -48,6 +48,7 @@ GTKOBJ += dnd.o
 GTKOBJ += headerbar.o
 GTKOBJ += webview.o
 GTKOBJ += widget.o
+GTKOBJ += action.o
 
 TOOLKITOBJS += $(GTKOBJ:%=$(GTK_OBJPRE)%)
 TOOLKITSOURCE += $(GTKOBJ:%.o=gtk/%.c)
index e9dc703e529318c422f9fdec6cad82ce916e3130..4ce3a40565a91e9802eabfc105885660112696c1 100644 (file)
@@ -54,9 +54,9 @@ static void selection_handler(
         int sel = gtk_text_buffer_get_selection_bounds (buf, &begin, &end);
         if(sel != textview->last_selection_state) {
             if(sel) {
-                ui_set_state(textview->ctx, UI_GROUP_SELECTION);
+                ui_set_state(textview->ctx, UI_STATE_SELECTION);
             } else {
-                ui_unset_state(textview->ctx, UI_GROUP_SELECTION);
+                ui_unset_state(textview->ctx, UI_STATE_SELECTION);
             }
         }
         textview->last_selection_state = sel;
@@ -102,6 +102,17 @@ static GtkTextBuffer* create_textbuffer(UiTextArea *textarea) {
                 "changed",
                 G_CALLBACK(ui_textbuf_changed),
                 textarea);
+        
+        g_signal_connect(
+                buf,
+                "insert-text",
+                G_CALLBACK(ui_textbuf_change_insert),
+                textarea);
+        g_signal_connect(
+                buf,
+                "delete-range",
+                G_CALLBACK(ui_textbuf_change_delete),
+                textarea); 
     } else {
         fprintf(stderr, "Error: create_textbuffer: textarea == NULL\n");
     }
@@ -129,6 +140,10 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
     uitext->last_selection_state = 0;
     uitext->onchange = args->onchange;
     uitext->onchangedata = args->onchangedata;
+    uitext->onchange_action = args->onchange_action ? strdup(args->onchange_action) : NULL;
+    uitext->ontextchanged = args->ontextchanged;
+    uitext->ontextchangeddata = args->ontextchangeddata;
+    uitext->ontextchanged_action = args->ontextchanged_action ? strdup(args->ontextchanged_action) : NULL;
     
     g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext);
     g_object_set_data(G_OBJECT(text_area), "ui_textarea_widget", text_area);
@@ -177,6 +192,11 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
                 value->value.free(value->value.ptr);
             }
         }
+        
+        if(value->readonly) {
+            gtk_text_view_set_editable(GTK_TEXT_VIEW(text_area), FALSE);
+        }
+        
         gtk_text_view_set_buffer(GTK_TEXT_VIEW(text_area), buf);
         value->obj = text_area;
         value->save = ui_textarea_save;
@@ -194,6 +214,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
         value->selection = ui_textarea_selection;
         value->length = ui_textarea_length;
         value->remove = ui_textarea_remove;
+        value->setreadonly = ui_textarea_setreadonly;
         value->data1 = buf;
         value->data2 = NULL;
         value->datatype == UI_TEXT_TYPE_BUFFER;
@@ -212,6 +233,8 @@ void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea) {
     if(textarea->var) {
         ui_destroy_boundvar(textarea->ctx, textarea->var);
     }
+    free(textarea->onchange_action);
+    free(textarea->ontextchanged_action);
     free(textarea);
 }
 
@@ -219,6 +242,7 @@ void ui_textarea_scroll_to(UIWIDGET textarea, int pos) {
     GtkWidget *widget = ui_textarea_gettextwidget(textarea);
     if(!widget) {
         fprintf(stderr, "Error: ui_textarea_scroll_to: widget is not a textarea\n");
+        return;
     }
     GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
     
@@ -228,6 +252,86 @@ void ui_textarea_scroll_to(UIWIDGET textarea, int pos) {
     gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget), &offset, 0.2, FALSE, 0, 0);
 }
 
+void ui_textarea_focus(UIWIDGET textarea) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_focus: widget is not a textarea\n");
+        return;
+    }
+    gtk_widget_grab_focus(widget);
+}
+
+void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_set_selection: widget is not a textarea\n");
+        return;
+    }
+    
+    GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
+    GtkTextIter ib;
+    GtkTextIter ie;
+    gtk_text_buffer_get_iter_at_offset(buf, &ib, begin);
+    gtk_text_buffer_get_iter_at_offset(buf, &ie, end);
+    gtk_text_buffer_select_range(buf, &ib, &ie);
+}
+
+void ui_textarea_select_all(UIWIDGET textarea) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_select_all: widget is not a textarea\n");
+        return;
+    }
+    GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
+    GtkTextIter start;
+    GtkTextIter end;
+    gtk_text_buffer_get_bounds(buf, &start, &end);
+    gtk_text_buffer_select_range(buf, &start, &end);
+}
+
+void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_set_editable: widget is not a textarea\n");
+        return;
+    }
+    gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), editable);
+}
+
+UiBool ui_textarea_is_editable(UIWIDGET textarea) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_is_editable: widget is not a textarea\n");
+        return 0;
+    }
+    return gtk_text_view_get_editable(GTK_TEXT_VIEW(widget));
+}
+
+void ui_textarea_set_position(UIWIDGET textarea, int pos) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_set_position: widget is not a textarea\n");
+        return;
+    }
+    GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
+    GtkTextIter iter;
+    gtk_text_buffer_get_iter_at_offset(buf, &iter, pos);
+    gtk_text_buffer_place_cursor(buf, &iter);
+}
+
+int ui_textarea_get_position(UIWIDGET textarea) {
+    GtkWidget *widget = ui_textarea_gettextwidget(textarea);
+    if(!widget) {
+        fprintf(stderr, "Error: ui_textarea_get_position: widget is not a textarea\n");
+        return 0;
+    }
+    GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
+    GtkTextIter begin;
+    GtkTextIter end;
+    gtk_text_buffer_get_selection_bounds(buf, &begin, &end);
+    return gtk_text_iter_get_offset(&begin);
+}
+
 UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) {
     return g_object_get_data(G_OBJECT(textarea), "ui_textarea_widget");
 }
@@ -243,6 +347,7 @@ void ui_textarea_restore(UiText *text) {
         text->datatype = UI_TEXT_TYPE_BUFFER;
     }
     gtk_text_view_set_buffer(GTK_TEXT_VIEW(textarea), text->data1);
+    gtk_text_view_set_editable(GTK_TEXT_VIEW(textarea), !text->readonly);
 }
 
 void ui_textarea_text_destroy(UiText *text) {
@@ -328,7 +433,9 @@ int ui_textarea_position(UiText *text) {
 }
 
 void ui_textarea_showposition(UiText *text, int pos) {
-    ui_textarea_scroll_to(text->obj, pos);
+    if(text->obj) {
+        ui_textarea_scroll_to(text->obj, pos);
+    }
 }
 
 void ui_textarea_setselection(UiText *text, int begin, int end) {
@@ -365,11 +472,72 @@ void ui_textarea_remove(UiText *text, int begin, int end) {
     gtk_text_buffer_delete(buf, &ib, &ie);
 }
 
+void ui_textarea_setreadonly(UiText *text, int readonly) {
+    if(text->obj) {
+        gtk_text_view_set_editable(GTK_TEXT_VIEW(text->obj), !readonly);
+    }
+    text->readonly = readonly;
+}
+
 void ui_textarea_realize_event(GtkWidget *widget, gpointer data) {
     gtk_widget_grab_focus(widget);
 }
 
 
+static void textbuf_change_event(UiTextArea *textarea, UiTextChangeEventData *data) {
+    if(!ui_onchange_events_is_enabled()) {
+        return;
+    }
+    
+    UiEvent e;
+    e.obj = textarea->obj;
+    e.window = e.obj->window;
+    e.document = textarea->ctx->document;
+    e.eventdata = data;
+    e.eventdatatype = UI_EVENT_DATA_TEXT_CHANGED;
+    e.intval = 0;
+    e.set = ui_get_setop();
+    
+    if(textarea->onchange) {
+        textarea->onchange(&e, textarea->onchangedata);
+    }
+    
+    if(textarea->onchange_action) {
+        uic_action_callback(&e, textarea->onchange_action);
+    }
+}
+
+void ui_textbuf_change_insert(
+        GtkTextBuffer *textbuffer,
+        GtkTextIter *location,
+        char *text,
+        int length,
+        UiTextArea *textarea)
+{
+    UiTextChangeEventData event;
+    event.type = UI_TEXT_INSERT;
+    event.begin = gtk_text_iter_get_offset(location);
+    event.end = event.begin + length;
+    event.text = text;
+    event.length = length;
+    textbuf_change_event(textarea, &event);
+}
+
+void ui_textbuf_change_delete(
+        GtkTextBuffer *self,
+        const GtkTextIter *start,
+        const GtkTextIter *end,
+        UiTextArea *textarea)
+{
+    UiTextChangeEventData event;
+    event.type = UI_TEXT_DELETE;
+    event.begin = gtk_text_iter_get_offset(start);
+    event.end = gtk_text_iter_get_offset(end);
+    event.text = NULL;
+    event.length = 0;
+    textbuf_change_event(textarea, &event);
+}
+
 
 void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
     if(!ui_onchange_events_is_enabled()) {
@@ -387,8 +555,12 @@ void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
     e.intval = 0;
     e.set = ui_get_setop();
     
-    if(textarea->onchange) {
-        textarea->onchange(&e, textarea->onchangedata);
+    if(textarea->ontextchanged) {
+        textarea->ontextchanged(&e, textarea->ontextchangeddata);
+    }
+    
+    if(textarea->ontextchanged_action) {
+        uic_action_callback(&e, textarea->ontextchanged_action);
     }
     
     if(value->observers) {
@@ -482,6 +654,7 @@ void ui_textbuf_delete(
     if(!value->data2) {
         value->data2 = ui_create_undomgr();
     }
+    GtkTextBuffer *buf = value->data1;
     UiUndoMgr *mgr = value->data2;
     if(!mgr->event) {
         return;
@@ -501,7 +674,7 @@ void ui_textbuf_delete(
         }
     }
     
-    char *text = gtk_text_buffer_get_text(value->obj, start, end, FALSE);
+    char *text = gtk_text_buffer_get_text(buf, start, end, FALSE);
     
     UiTextBufOp *op = malloc(sizeof(UiTextBufOp));
     op->prev = NULL;
@@ -577,6 +750,7 @@ int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) {
 }
 
 void ui_text_undo(UiText *value) {
+    GtkTextBuffer *buf = value->data1;
     UiUndoMgr *mgr = value->data2;
     
     if(mgr->cur) {
@@ -586,17 +760,17 @@ void ui_text_undo(UiText *value) {
             case UI_TEXTBUF_INSERT: {
                 GtkTextIter begin;
                 GtkTextIter end;
-                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
-                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
-                gtk_text_buffer_delete(value->obj, &begin, &end);
+                gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(buf, &end, op->end);
+                gtk_text_buffer_delete(buf, &begin, &end);
                 break;
             }
             case UI_TEXTBUF_DELETE: {
                 GtkTextIter begin;
                 GtkTextIter end;
-                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
-                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
-                gtk_text_buffer_insert(value->obj, &begin, op->text, op->len);
+                gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(buf, &end, op->end);
+                gtk_text_buffer_insert(buf, &begin, op->text, op->len);
                 break;
             }
         }
@@ -606,6 +780,7 @@ void ui_text_undo(UiText *value) {
 }
 
 void ui_text_redo(UiText *value) {
+    GtkTextBuffer *buf = value->data1;
     UiUndoMgr *mgr = value->data2;
     
     UiTextBufOp *elm = NULL;
@@ -624,17 +799,17 @@ void ui_text_redo(UiText *value) {
             case UI_TEXTBUF_INSERT: {
                 GtkTextIter begin;
                 GtkTextIter end;
-                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
-                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
-                gtk_text_buffer_insert(value->obj, &begin, op->text, op->len);
+                gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(buf, &end, op->end);
+                gtk_text_buffer_insert(buf, &begin, op->text, op->len);
                 break;
             }
             case UI_TEXTBUF_DELETE: {
                 GtkTextIter begin;
                 GtkTextIter end;
-                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
-                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
-                gtk_text_buffer_delete(value->obj, &begin, &end);
+                gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(buf, &end, op->end);
+                gtk_text_buffer_delete(buf, &begin, &end);
                 break;
             }
         }
@@ -660,6 +835,8 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
     uitext->onchangedata = args->onchangedata;
     uitext->onactivate = args->onactivate;
     uitext->onactivatedata = args->onactivatedata;
+    uitext->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
+    uitext->onchange_action = args->onchange_action ? strdup(args->onchange_action) : NULL;
     
     g_signal_connect(
                 textfield,
@@ -703,7 +880,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
         value->obj = GTK_ENTRY(textfield);
     }
     
-    if(args->onchange || var) {
+    if(args->onchange || args->onchange_action || var) {
         g_signal_connect(
                 textfield,
                 "changed",
@@ -711,7 +888,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
                 uitext);
     }
     
-    if(args->onactivate) {
+    if(args->onactivate || args->onactivate_action) {
         g_signal_connect(
                 textfield,
                 "activate",
@@ -771,6 +948,8 @@ int ui_textfield_get_position(UIWIDGET textfield) {
 }
 
 void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) {
+    free(textfield->onactivate_action);
+    free(textfield->onchange_action);
     free(textfield);
 }
 
@@ -786,7 +965,7 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
     e.window = e.obj->window;
     e.document = textfield->obj->ctx->document;
     e.eventdata = value;
-    e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
+    e.eventdatatype = value ? UI_EVENT_DATA_STRING_VALUE : 0;
     e.intval = 0;
     e.set = ui_get_setop();
     
@@ -797,22 +976,31 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
     if(textfield->var) {
         ui_notify_evt(value->observers, &e);
     }
+    
+    if(textfield->onchange_action) {
+        uic_action_callback(&e, textfield->onchange_action);
+    }
 }
 
 void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
-    if(textfield->onactivate) {
-        UiString *value = textfield->var ? textfield->var->value : NULL;
+    UiString *value = textfield->var ? textfield->var->value : NULL;
         
-        UiEvent e;
-        e.obj = textfield->obj;
-        e.window = e.obj->window;
-        e.document = textfield->obj->ctx->document;
-        e.eventdata = value;
-        e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
-        e.intval = 0;
-        e.set = ui_get_setop();
+    UiEvent e;
+    e.obj = textfield->obj;
+    e.window = e.obj->window;
+    e.document = textfield->obj->ctx->document;
+    e.eventdata = value;
+    e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
+    e.intval = 0;
+    e.set = ui_get_setop();
+    
+    if(textfield->onactivate) {
         textfield->onactivate(&e, textfield->onactivatedata);
     }
+    
+    if(textfield->onactivate_action) {
+        uic_action_callback(&e, textfield->onactivate_action);
+    }
 }
 
 char* ui_textfield_get(UiString *str) {
index 4d306aa5026cadf9ffb9c5d3675a5974f9742e61..cb12ea1d788d25c571f185e6f0810b8d05a9b86a 100644 (file)
@@ -67,6 +67,10 @@ typedef struct UiTextArea {
     int         last_selection_state;
     ui_callback onchange;
     void        *onchangedata;
+    char        *onchange_action;
+    ui_callback ontextchanged;
+    void        *ontextchangeddata;
+    char        *ontextchanged_action;
 } UiTextArea;
 
 typedef struct UiTextField {
@@ -76,6 +80,8 @@ typedef struct UiTextField {
     void        *onchangedata;
     ui_callback onactivate;
     void        *onactivatedata;
+    char        *onactivate_action;
+    char        *onchange_action;
 } UiTextField;
 
 typedef struct UiPathTextField {
@@ -126,8 +132,22 @@ void ui_textarea_setselection(UiText *text, int begin, int end);
 void ui_textarea_selection(UiText *text, int *begin, int *end);
 int ui_textarea_length(UiText *text);
 void ui_textarea_remove(UiText *text, int begin, int end);
+void ui_textarea_setreadonly(UiText *text, int readonly);
 
 void ui_textarea_realize_event(GtkWidget *widget, gpointer data);
+//void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea);
+void ui_textbuf_change_insert(
+        GtkTextBuffer *textbuffer,
+        GtkTextIter *location,
+        char *text,
+        int length,
+        UiTextArea *textarea);
+void ui_textbuf_change_delete(
+        GtkTextBuffer *self,
+        const GtkTextIter *start,
+        const GtkTextIter *end,
+        UiTextArea *textarea);
+
 void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea);
 
 void ui_textbuf_insert(
index 33efbcd274eb1cbf575094b90985dfe84b2e7a13..1f6cc19f680161ab2405220bdef55889236e2514 100644 (file)
@@ -140,13 +140,14 @@ void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) {
     
     ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates);
     
-    if(item->args.onclick) {
+    if(item->args.onclick || item->args.action) {
         UiEventData *event = cxMalloc(
                 obj->ctx->allocator,
                 sizeof(UiEventData));
         event->obj = obj;
         event->callback = item->args.onclick;
         event->userdata = item->args.onclickdata;
+        event->action = item->args.action ? ui_strdup(obj->ctx, item->args.action) : NULL;
         event->customdata = NULL;
         event->customint = 0;
         event->value = 0;
@@ -202,6 +203,7 @@ void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObj
     event->obj = obj;
     event->callback = item->args.onchange;
     event->userdata = item->args.onchangedata;
+    event->action = item->args.action ? ui_strdup(obj->ctx, item->args.action) : NULL;;
     event->var = var;
 
     g_signal_connect(
@@ -239,6 +241,10 @@ void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event)
     if(i) {
         ui_notify_evt(i->observers, &e);
     }
+    
+    if(event->action) {
+        uic_action_callback(&e, event->action);
+    }
 }
 
 int64_t ui_tool_toggle_button_get(UiInteger *integer) {
index 7534c63ec6caea97858e57f237de3dcc37da755b..659e9cbc84474c7b86221359174894e2700fe2d0 100644 (file)
@@ -42,68 +42,6 @@ extern "C" {
 
 #if UI_GTK2 || UI_GTK3
     
-typedef struct UiToolItemI      UiToolItemI;
-typedef struct UiToolItem       UiToolItem;
-typedef struct UiStToolItem     UiStToolItem;
-typedef struct UiToggleToolItem UiToggleToolItem;
-
-typedef struct UiToolbarComboBox   UiToolbarComboBox;
-typedef struct UiToolbarComboBoxNV UiToolbarComboBoxNV;
-
-typedef void(*ui_toolbar_add_f)(GtkToolbar*, UiToolItemI*, UiObject*);
-
-struct UiToolItemI {
-    ui_toolbar_add_f  add_to;
-};
-
-struct UiToolItem {
-    UiToolItemI    item;
-    const char     *label;
-    const char     *image;
-    ui_callback    callback;
-    void           *userdata;
-    const char     *varname;
-    CxList         *groups;
-    int            isimportant;
-};
-
-struct UiStToolItem {
-    UiToolItemI    item;
-    const char     *stockid;
-    ui_callback    callback;
-    void           *userdata;
-    const char     *varname;
-    CxList         *groups;
-    int            isimportant;
-};
-
-struct UiToggleToolItem {
-    UiToolItemI    item;
-    const char     *label;
-    const char     *image;
-    const char     *stockid;
-    UiInteger      *value;
-    const char     *var;
-    CxList         *groups;
-    int            isimportant;
-};
-
-struct UiToolbarComboBox {
-    UiToolItemI         item;
-    UiVar               *var;
-    ui_getvaluefunc getvalue;
-    ui_callback         callback;
-    void                *userdata;
-};
-
-struct UiToolbarComboBoxNV {
-    UiToolItemI         item;
-    char                *listname;
-    ui_getvaluefunc     getvalue;
-    ui_callback         callback;
-    void                *userdata;
-};
-
 
 void ui_toolitem_vstgr(
         char *name,
index f974baea12e5f0c8f8fac6efedaf0ca1e897f41b..dbdde0a91164fbdcc36a09352bc3ce1380478a29 100644 (file)
@@ -62,8 +62,11 @@ static int scale_factor = 1;
 
 static UiBool        exit_on_shutdown;
 
+// NOOP on most platforms, expect macos
+void ui_set_main_thread_error_msg(const char *msg) {}
+
 UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
-    application_name = appname;
+    application_name = appname ? strdup(appname) : NULL;
     uic_init_global_context();
     
 #if GTK_MAJOR_VERSION >= 4
@@ -165,7 +168,6 @@ GtkApplication* ui_get_application() {
 
 void ui_show(UiObject *obj) {
     gboolean visible = FALSE;
-    uic_check_state_widgets(obj->ctx);
     if(obj->widget) {
         visible = gtk_widget_is_visible(obj->widget);
 #if GTK_MAJOR_VERSION >= 4
@@ -174,6 +176,7 @@ void ui_show(UiObject *obj) {
         gtk_widget_show_all(obj->widget);
 #endif
     }
+    uic_check_state_widgets(obj->ctx);
       
     if(!visible) {
         obj->ref++;
@@ -181,16 +184,7 @@ void ui_show(UiObject *obj) {
 }
 
 void ui_close(UiObject *obj) {
-    uic_context_prepare_close(obj->ctx); // TODO: should this be moved to the close event handler?
-    if(obj->widget) {
-#if GTK_CHECK_VERSION(4, 0, 0)
-        gtk_window_close(GTK_WINDOW(obj->widget));
-#else
-        gtk_widget_destroy(obj->widget);
-#endif
-    } else {
-        ui_window_close_request(obj);
-    }
+    ui_window_close_request(obj);
 }
 
 
@@ -265,7 +259,7 @@ void ui_set_show_all(UIWIDGET widget, int value) {
 #endif
 }
 
-void ui_set_visible(UIWIDGET widget, UiBool visible) {
+void ui_set_visible(UIWIDGET widget, int visible) {
 #if GTK_MAJOR_VERSION >= 4
     gtk_widget_set_visible(widget, visible);
 #else
@@ -313,6 +307,11 @@ void ui_destroy_userdata(GtkWidget *object, void *userdata) {
     free(userdata);
 }
 
+void ui_destroy_eventdata(GtkWidget *object, UiEventData *data) {
+    free(data->action);
+    free(data);
+}
+
 void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data) {
     if(data->var) {
         ui_destroy_boundvar(data->obj->ctx, data->var);
@@ -567,3 +566,16 @@ void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const i
         ui_set_visible(widget, FALSE);
     }
 }
+
+void ui_open_uri(const char *uri) {
+#if GTK_CHECK_VERSION(4, 0, 0)
+    GtkUriLauncher *launcher = gtk_uri_launcher_new(uri);
+    gtk_uri_launcher_launch(launcher, NULL, NULL, NULL, NULL);
+    g_object_unref(launcher);
+#elif GTK_CHECK_VERSION(3, 22, 0)
+    GError *error = NULL;
+    gtk_show_uri_on_window(NULL, uri, GDK_CURRENT_TIME, &error);
+#elif
+    // TODO: call xdg-open
+#endif
+}
index e16f3614806e243ca48f9049eb55da26f8aacce5..432bebb9dad1e766f0678c86abcbc67f3ec46be7 100644 (file)
@@ -149,6 +149,7 @@ typedef struct UiEventData {
     int         value;
     int         customint;
     void        *customdata;
+    char        *action;
 } UiEventData;
 
 typedef struct UiEventDataExt {
@@ -172,6 +173,7 @@ typedef struct UiVarEventData {
     UiVar       *var;
     UiObserver  **observers;
     ui_callback callback;
+    char        *action;
     void        *userdata;
     int         customint1;
     int         customint2;
@@ -200,6 +202,7 @@ void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const in
 void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
 
 void ui_destroy_userdata(GtkWidget *object, void *userdata);
+void ui_destroy_eventdata(GtkWidget *object, UiEventData *data);
 void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data);
 void ui_destroy_widget_var(GtkWidget *object, UiVar *var);
 void ui_destroy_boundvar(UiContext *ctx, UiVar *var);
index 58af741ff25051a9a9ae334b9b42b2a7f1ff0a6a..009d432cac07cd802c7be67fa485ef4147ecb470 100644 (file)
@@ -45,6 +45,7 @@
 #include "headerbar.h"
 #include "button.h"
 #include "window.h"
+#include "widget.h"
 
 static int nwindows = 0;
 
@@ -112,7 +113,12 @@ gboolean ui_window_close_request(UiObject *obj) {
         }
     }
     
-    obj->ref--;
+    if(obj->ref > 0) {
+        obj->ref--;
+    } else {
+        // warn about invalid reference counting
+        fprintf(stderr, "Error: UiObject %p ref == 0\n", obj);
+    }
     if(obj->ref > 0) {
 #if GTK_CHECK_VERSION(2, 18, 0)
         gtk_widget_set_visible(obj->widget, FALSE);
@@ -121,29 +127,32 @@ gboolean ui_window_close_request(UiObject *obj) {
 #endif
         return TRUE;
     } else {
-        if(obj->ctx->close_callback) {
-            UiEvent ev;
-            ev.window = obj->window;
-            ev.document = obj->ctx->document;
-            ev.obj = obj;
-            ev.eventdata = NULL;
-            ev.eventdatatype = 0;
-            ev.intval = 0;
-            obj->ctx->close_callback(&ev, obj->ctx->close_data);
-            obj->ctx->close_callback = NULL;
-        }
-        
+        // this cleans up any widget references from the context
         uic_context_prepare_close(obj->ctx);
+        ui_window_widget_destroy(obj);
         return FALSE;
     }
 }
 
+static void window_onclose_callback(UiObject *obj) {
+    if(obj->onclose) {
+        UiEvent event;
+        memset(&event, 0, sizeof(UiEvent));
+        event.obj = obj;
+        event.window = obj->window;
+        event.document = obj->ctx->document;
+        obj->onclose(&event, obj->onclosedata);
+    }
+}
+
 #if GTK_MAJOR_VERSION >= 4
 static gboolean close_request(GtkWindow* self, UiObject *obj) {
+    window_onclose_callback(obj);
     return ui_window_close_request(obj);
 }
 #else
 static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) {
+    window_onclose_callback(obj);
     return ui_window_close_request(obj);
 }
 #endif
@@ -278,6 +287,8 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi
         g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content);
         g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", vbox);
         g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_vbox);
+        g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel_top", toolbar_view);
+        g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel_top", right_panel);
     }
     
     GtkWidget *content_box = vbox;
@@ -305,17 +316,23 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi
             adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
         } else if(!strcmp(show_title, "sidebar")) {
             adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
-            adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE);
+            if(headerbar_sidebar) {
+                adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE);
+            }
         } else if(!strcmp(show_title, "false")) {
-            adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+            if(headerbar_sidebar) {
+                adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+            }
             adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
         } else {
             fprintf(stderr, "Unknown value '%s' for property ui.gtk.window.showtitle\n", show_title);
-            adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+            if(headerbar_sidebar) {
+                adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+            }
         }
     } else {
         adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
-        if(sidebar) {
+        if(headerbar_sidebar) {
             adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE);
         }
     }
@@ -374,6 +391,8 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi
             g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content_paned);
             g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", content_box);
             g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_content_box);
+            g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel_top", content_box);
+            g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel_top", right_content_box);
         } else {
             PANED_SET_CHILD2(paned, content_box);
         }
@@ -398,7 +417,7 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi
     gtk_container_add(GTK_CONTAINER(frame), content_box);
     obj->container = ui_box_container(obj, content_box);
     */
-    UiContainerX *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
+    UiContainer *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
     uic_object_push_container(obj, container);
     
     nwindows++;
@@ -463,10 +482,13 @@ void ui_splitview_window_use_property(UiBool enable) {
 
 UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool visible) {
     GtkWidget *panel = NULL;
+    CxList *backup_items = NULL;
     if(pane == 0) {
-        panel = g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel");
+        panel = g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel_top");
+        backup_items = g_object_get_data(G_OBJECT(obj->widget), "ui_toolbar_center_backup");
     } else if(pane == 1) {
-        panel = g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel");
+        panel = g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel_top");
+        // TODO: backup toolbar items
     }
     
     if(panel == NULL) {
@@ -475,6 +497,13 @@ UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool vi
     }
     
     gtk_widget_set_visible(panel, visible);
+    
+    if(backup_items) {
+        CxIterator i = cxListIterator(backup_items);
+        cx_foreach(GtkWidget*, w, i) {
+            ui_set_visible(w, !visible);
+        }
+    }
 }
 
 #ifdef UI_LIBADWAITA
@@ -503,6 +532,8 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
     if(data->callback) {
         data->callback(&evt, data->userdata);
     }
+    
+    ui_app_unref();
 }
 
 void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
@@ -547,7 +578,8 @@ void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
                 event);
     
     g_signal_connect(dialog, "response", G_CALLBACK(dialog_response), event);
-    adw_dialog_present(dialog, parent->widget);
+    ui_app_ref();
+    adw_dialog_present(dialog, parent ? parent->widget : NULL);
     
     if(entry) {
         gtk_entry_grab_focus_without_selecting(GTK_ENTRY(entry));
@@ -559,8 +591,14 @@ static void ui_dialog_response (GtkDialog* self, gint response_id, gpointer user
     UiEventData *data = user_data;
     UiEvent evt;
     evt.obj = data->obj;
-    evt.document = evt.obj->ctx->document;
-    evt.window = evt.obj->window;
+    if(evt.obj) {
+        evt.document = evt.obj->ctx->document;
+        evt.window = evt.obj->window;
+    } else {
+        evt.document = NULL;
+        evt.window = NULL;
+    }
+    
     evt.eventdata = NULL;
     evt.intval = 0;
     
@@ -975,7 +1013,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
 #endif
     
     GtkWidget *content_vbox = ui_gtk_vbox_new(0);
-    UiContainerX *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
+    UiContainer *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
     uic_object_push_container(obj, container);
     if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) {
 #if GTK_CHECK_VERSION(3, 10, 0)
@@ -987,7 +1025,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
             }
             
             if(args->lbutton1) {
-                GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1);
+                GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 1, args->default_button == 1);
                 gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
                 if(args->default_button == 1) {
                     WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -995,7 +1033,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
                 }
             }
             if(args->lbutton2) {
-                GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2);
+                GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 2, args->default_button == 2);
                 gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
                 if(args->default_button == 2) {
                     WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1004,7 +1042,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
             }
             
             if(args->rbutton4) {
-                GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4);
+                GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 4, args->default_button == 4);
                 gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
                 if(args->default_button == 4) {
                     WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1012,7 +1050,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
                 }
             }
             if(args->rbutton3) {
-                GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3);
+                GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 3, args->default_button == 3);
                 gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
                 if(args->default_button == 3) {
                     WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1033,7 +1071,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
         gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); 
         
         if(args->lbutton1) {
-            GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1);
+            GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 1, args->default_button == 1);
             gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
             if(args->default_button == 1) {
                 WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1041,7 +1079,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
             }
         }
         if(args->lbutton2) {
-            GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2);
+            GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 2, args->default_button == 2);
             gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
             if(args->default_button == 2) {
                 WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1052,7 +1090,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
         gtk_widget_set_hexpand(space, TRUE);
         gtk_grid_attach(GTK_GRID(grid), space, 2, 0, 1, 1);
         if(args->rbutton3) {
-            GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3);
+            GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 3, args->default_button == 3);
             gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1);
             if(args->default_button == 3) {
                 WIDGET_ADD_CSS_CLASS(button, "suggested-action");
@@ -1060,7 +1098,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
             }
         }
         if(args->rbutton4) {
-            GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4);
+            GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 4, args->default_button == 4);
             gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1);
             if(args->default_button == 4) {
                 WIDGET_ADD_CSS_CLASS(button, "suggested-action");
diff --git a/ui/gtk/window.h b/ui/gtk/window.h
new file mode 100644 (file)
index 0000000..1b85fd9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include "toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+gboolean ui_window_close_request(UiObject *obj);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WINDOW_H */
+
index c7db3968f8bf049f10ab16d6f73f8c40d31cc053..ae9155f7fa110b91dc55460b69831cfbb3b15113 100644 (file)
@@ -63,7 +63,8 @@ typedef struct UiButtonArgs {
     const char *tooltip;
     UiLabelType labeltype;
     ui_callback onclick;
-    void *onclickdata;
+    void        *onclickdata;
+    const char  *action;
     
     const int *states;
     const int *visibility_states;
@@ -86,20 +87,58 @@ typedef struct UiToggleArgs {
     const char *name;
     const char *style_class;
     
-    const char *label;
-    const char *icon;
-    const char *tooltip;
+    const char  *label;
+    const char  *icon;
+    const char  *tooltip;
     UiLabelType labeltype;
-    UiInteger *value;
-    const char *varname;
+    UiInteger   *value;
+    const char  *varname;
     ui_callback onchange;
-    void *onchangedata;
-    int enable_state;
+    void        *onchangedata;
+    const char  *action;
+    int         enable_state;
     
-    const int *states;
-    const int *visibility_states;
+    const int   *states;
+    const int   *visibility_states;
 } UiToggleArgs;
 
+typedef struct UiContentToggleArgs {
+    UiBool fill;
+    UiBool hexpand;
+    UiBool vexpand;
+    UiBool hfill;
+    UiBool vfill;
+    UiBool override_defaults;
+    int margin;
+    int margin_left;
+    int margin_right;
+    int margin_top;
+    int margin_bottom;
+    int colspan;
+    int rowspan;
+    const char *name;
+    const char *style_class;
+    
+    const char  *label0;
+    const char  *icon0;
+    const char  *tooltip0;
+    const char  *label1;
+    const char  *icon1;
+    const char  *tooltip1;
+    UiLabelType labeltype;
+    UiInteger   *value;
+    const char  *varname;
+    ui_callback onchange;
+    void        *onchangedata;
+    const char  *action;
+    UiBool      istogglebutton;
+    int         enable_state;
+    int         toggled_by_state;
+    
+    const int   *states;
+    const int   *visibility_states;
+} UiContentToggleArgs;
+
 typedef struct UiLinkButtonArgs {
     UiBool fill;
     UiBool hexpand;
@@ -123,6 +162,7 @@ typedef struct UiLinkButtonArgs {
     const char *varname;
     ui_callback onclick;
     void *onclickdata;
+    const char *action;
     UiBool nofollow;
     UiLinkType type;
     
@@ -134,6 +174,7 @@ typedef struct UiLinkButtonArgs {
 #define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
 #define ui_checkbox(obj, ...) ui_checkbox_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
 #define ui_switch(obj, ...) ui_switch_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_content_togglebutton(obj, ...) ui_content_togglebutton_create(obj, &(UiContentToggleArgs){ __VA_ARGS__ } )
 #define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
 #define ui_linkbutton(obj, ...) ui_linkbutton_create(obj, &(UiLinkButtonArgs){ __VA_ARGS__ })
 
@@ -141,11 +182,25 @@ UIEXPORT UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args);
 UIEXPORT UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args);
 UIEXPORT UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args);
 UIEXPORT UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_content_togglebutton_create(UiObject *obj, UiContentToggleArgs *args);
 UIEXPORT UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args);
 UIEXPORT UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args);
 
 UIEXPORT void ui_button_set_label(UIWIDGET button, const char *label);
 UIEXPORT void ui_button_set_icon(UIWIDGET button, const char *icon);
+UIEXPORT void ui_button_set_tooltip(UIWIDGET button, const char *tooltip);
+
+UIEXPORT void ui_togglebutton_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_togglebutton_set_icon(UIWIDGET button, const char *icon);
+UIEXPORT void ui_togglebutton_set_tooltip(UIWIDGET button, const char *tooltip);
+
+UIEXPORT void ui_checkbox_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_checkbox_set_icon(UIWIDGET button, const char *icon);
+UIEXPORT void ui_checkbox_set_tooltip(UIWIDGET button, const char *tooltip);
+
+UIEXPORT void ui_radiobutton_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_radiobutton_set_icon(UIWIDGET button, const char *icon);
+UIEXPORT void ui_radiobutton_set_tooltip(UIWIDGET button, const char *tooltip);
 
 UIEXPORT void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri);
 UIEXPORT void ui_linkbutton_value_set_label(UiString *str, const char *label);
index 49bc6316858115033d9ace3082ae7203f5b589f6..187f22107f624271f6a8773fd35762c6880cc568 100644 (file)
@@ -285,12 +285,12 @@ struct UiLayout {
     int          rowspan;
 };
 
-struct UiContainerX {
+struct UiContainer {
     void *container;
     UiBool close;
     UiBool newline;
-    UiContainerX *prev;
-    UiContainerX *next;
+    UiContainer *prev;
+    UiContainer *next;
 };
 
 
@@ -381,10 +381,6 @@ UIEXPORT void ui_newline(UiObject *obj);
 typedef void(*ui_addwidget_func)(UiObject *obj, UIWIDGET parent, UIWIDGET child, void *userdata);
 UIEXPORT void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_func add_child, void *userdata);
 
-// TODO
-UIEXPORT UiTabbedPane* ui_tabbed_document_view(UiObject *obj);
-UIEXPORT UiObject* ui_document_tab(UiTabbedPane *view);
-
 
 
 /* used for macro */
index 9bc86a44927ced04df40d59a9cfd3c62ab5ed490..2b5540f1a9d625365165f1c36606e79c91ba5769 100644 (file)
@@ -38,23 +38,139 @@ extern "C" {
 #ifdef UI_GTK
     
 #define UI_ICON_HOME "go-home"
-#define UI_ICON_NEW_WINDOW "list-add"
-#define UI_ICON_REFRESH "view-refresh"
+#define UI_ICON_NEW_WINDOW "window-new"
+#define UI_ICON_NEW_TAB "tab-new"
 #define UI_ICON_NEW_FOLDER "folder-new"
-#define UI_ICON_ADD "document-new"
+#define UI_ICON_NEW_DOCUMENT "document-new"
+#define UI_ICON_NEW_APPOINTMENT "appointment-new"
+#define UI_ICON_NEW_CHAT_MESSAGE "chat-message-new"
+#define UI_ICON_NEW_CONTACT "contact-new"
+#define UI_ICON_NEW_MAIL "mail-message-new"
+#define UI_ICON_ADD_BOOKMARK "bookmark-new"
+#define UI_ICON_ADD_IMAGE "insert-image"
+#define UI_ICON_ADD_LINK "insert-link"
+#define UI_ICON_ADD_TEXT "insert-text"
+#define UI_ICON_ADD "list-add"
+#define UI_ICON_REMOVE "list-remove"
+#define UI_ICON_REFRESH "view-refresh"
 #define UI_ICON_UPLOAD "document-open"
 #define UI_ICON_SAVE_LOCAL "document-save-as"
-#define UI_ICON_DELETE "edit-delete"
-#define UI_ICON_DOCK_LEFT ""
-#define UI_ICON_DOCK_RIGHT ""
+#define UI_ICON_EDIT_COPY "edit-copy"
+#define UI_ICON_EDIT_CUT "edit-cut"
+#define UI_ICON_EDIT_DELETE "edit-delete"
+#define UI_ICON_EDIT_PASTE "edit-paste"
+#define UI_ICON_UNDO "edit-undo"
+#define UI_ICON_REDO "edit-redo"
+#define UI_ICON_SIDEBAR_LEFT "sidebar-show"
+#define UI_ICON_SIDEBAR_RIGHT "sidebar-show-right"
 #define UI_ICON_GO_BACK "go-previous"
 #define UI_ICON_GO_FORWARD "go-next"
 #define UI_ICON_GO_UP "go-up"
 #define UI_ICON_GO_DOWN "go-down"
+#define UI_ICON_VIEW_LIST "view-list"
+#define UI_ICON_VIEW_GRID "view-grid"
+#define UI_ICON_VIEW_DUAL "view-dual"
+#define UI_ICON_VIEW_FULLSCREEN "view-fullscreen"
+#define UI_ICON_VIEW_RESTORE "view-restore"
+#define UI_ICON_TEXT_BOLD "format-text-bold"
+#define UI_ICON_TEXT_ITALIC "format-text-italic"
+#define UI_ICON_TEXT_UNDERLINE "format-text-underline"
+#define UI_ICON_LIST_BULLET "view-list-bullet"
+#define UI_ICON_LIST_ORDERED "view-list-ordered"
+#define UI_ICON_LIST_CHECK "checkbox-checked"
+#define UI_ICON_CHECKBOX "checkbox-checked"
+#define UI_ICON_STAR "starred"
+#define UI_ICON_VIEW_REVEAL "view-reveal"
+#define UI_ICON_VIEW_CONCEAL "view-conceal"
+#define UI_ICON_SETTINGS "applications-system"
+#define UI_ICON_MEDIA_PLAY "media-playback-start"
+#define UI_ICON_MEDIA_STOP "media-playback-stop"
+#define UI_ICON_MEDIA_PAUSE "media-playback-pause"
+#define UI_ICON_MEDIA_SEEK_BACKWARD "media-seek-backward"
+#define UI_ICON_MEDIA_SEEK_FORWARD "media-seek-forward"
+#define UI_ICON_MEDIA_SKIP_BACKWARD "media-skip-backward"
+#define UI_ICON_MEDIA_SKIP_FORWARD "media-skip-forward"
+#define UI_ICON_CALL_START "call-start"
+#define UI_ICON_CALL_STOP "call-stop"
+#define UI_ICON_CALL_INCOMING "call-incoming"
+#define UI_ICON_CALL_OUTGOING "call-outgoing"
+#define UI_ICON_MICROPHONE_ON "microphone-sensitivity-high"
+#define UI_ICON_MICROPHONE_OFF "microphone-disabled"
+#define UI_ICON_LOCKED "changes-allow"
+#define UI_ICON_UNLOCKED "changes-prevent"
+#define UI_ICON_SECURE "channel-secure"
+#define UI_ICON_INSECURE "channel-insecure"
+    
     
 #endif /* UI_GTK */
     
+#ifdef UI_QT
+    
+#define UI_ICON_HOME "go-home"
+#define UI_ICON_NEW_WINDOW "window-new"
+#define UI_ICON_NEW_TAB "tab-new"
+#define UI_ICON_NEW_FOLDER "folder-new"
+#define UI_ICON_NEW_DOCUMENT "document-new"
+#define UI_ICON_NEW_APPOINTMENT "appointment-new"
+#define UI_ICON_NEW_CHAT_MESSAGE "chat-message-new"
+#define UI_ICON_NEW_CONTACT "contact-new"
+#define UI_ICON_NEW_MAIL "mail-message-new"
+#define UI_ICON_ADD_BOOKMARK "bookmark-new"
+#define UI_ICON_ADD_IMAGE "insert-image"
+#define UI_ICON_ADD_LINK "insert-link"
+#define UI_ICON_ADD_TEXT "insert-text"
+#define UI_ICON_ADD "list-add"
+#define UI_ICON_REMOVE "list-remove"
+#define UI_ICON_REFRESH "view-refresh"
+#define UI_ICON_UPLOAD "document-open"
+#define UI_ICON_SAVE_LOCAL "document-save-as"
+#define UI_ICON_EDIT_COPY "edit-copy"
+#define UI_ICON_EDIT_CUT "edit-cut"
+#define UI_ICON_EDIT_DELETE "edit-delete"
+#define UI_ICON_EDIT_PASTE "edit-paste"
+#define UI_ICON_UNDO "edit-undo"
+#define UI_ICON_REDO "edit-redo"
+#define UI_ICON_SIDEBAR_LEFT "sidebar-show"
+#define UI_ICON_SIDEBAR_RIGHT "sidebar-show-right"
+#define UI_ICON_GO_BACK "go-previous"
+#define UI_ICON_GO_FORWARD "go-next"
+#define UI_ICON_GO_UP "go-up"
+#define UI_ICON_GO_DOWN "go-down"
+#define UI_ICON_VIEW_LIST "view-list"
+#define UI_ICON_VIEW_GRID "view-grid"
+#define UI_ICON_VIEW_DUAL "view-dual"
+#define UI_ICON_VIEW_FULLSCREEN "view-fullscreen"
+#define UI_ICON_VIEW_RESTORE "view-restore"
+#define UI_ICON_TEXT_BOLD "format-text-bold"
+#define UI_ICON_TEXT_ITALIC "format-text-italic"
+#define UI_ICON_TEXT_UNDERLINE "format-text-underline"
+#define UI_ICON_LIST_BULLET "view-list-bullet"
+#define UI_ICON_LIST_ORDERED "view-list-ordered"
+#define UI_ICON_LIST_CHECK "checkbox-checked"
+#define UI_ICON_CHECKBOX "checkbox-checked"
+#define UI_ICON_STAR "starred"
+#define UI_ICON_VIEW_REVEAL "view-reveal"
+#define UI_ICON_VIEW_CONCEAL "view-conceal"
+#define UI_ICON_SETTINGS "applications-system"
+#define UI_ICON_MEDIA_PLAY "media-playback-start"
+#define UI_ICON_MEDIA_STOP "media-playback-stop"
+#define UI_ICON_MEDIA_PAUSE "media-playback-pause"
+#define UI_ICON_MEDIA_SEEK_BACKWARD "media-seek-backward"
+#define UI_ICON_MEDIA_SEEK_FORWARD "media-seek-forward"
+#define UI_ICON_MEDIA_SKIP_BACKWARD "media-skip-backward"
+#define UI_ICON_MEDIA_SKIP_FORWARD "media-skip-forward"
+#define UI_ICON_CALL_START "call-start"
+#define UI_ICON_CALL_STOP "call-stop"
+#define UI_ICON_CALL_INCOMING "call-incoming"
+#define UI_ICON_CALL_OUTGOING "call-outgoing"
+#define UI_ICON_MICROPHONE_ON "microphone-sensitivity-high"
+#define UI_ICON_MICROPHONE_OFF "microphone-disabled"
+#define UI_ICON_LOCKED "changes-allow"
+#define UI_ICON_UNLOCKED "changes-prevent"
+#define UI_ICON_SECURE "channel-secure"
+#define UI_ICON_INSECURE "channel-insecure"
     
+#endif /* UI_QT */
 
 #ifdef UI_WINUI
     
@@ -72,9 +188,280 @@ extern "C" {
 #define UI_ICON_GO_FORWARD "Forward"
 #define UI_ICON_GO_UP "Up"
 #define UI_ICON_GO_DOWN "" // TODO: implement workaround for missing down symbol
+#define UI_ICON_LIST "List"
     
 #endif /* UI_WINUI */
+
+#ifdef UI_COCOA
+
+#define UI_ICON_HOME "go-home"
+#define UI_ICON_NEW_WINDOW "macwindow.badge.plus"
+#define UI_ICON_NEW_TAB "plus.square"
+#define UI_ICON_NEW_FOLDER "folder.badge.plus"
+#define UI_ICON_NEW_DOCUMENT "document.badge.plus"
+#define UI_ICON_NEW_APPOINTMENT "calendar.badge.plus"
+#define UI_ICON_NEW_CHAT_MESSAGE "plus.bubble"
+#define UI_ICON_NEW_CONTACT "person.badge.plus"
+#define UI_ICON_NEW_MAIL "envelope.badge.plus"
+#define UI_ICON_ADD_BOOKMARK "book.badge.plus"
+#define UI_ICON_ADD_IMAGE "photo.badge.plus"
+#define UI_ICON_ADD_LINK "link.badge.plus"
+#define UI_ICON_ADD_TEXT "text.badge.plus"
+#define UI_ICON_ADD "plus"
+#define UI_ICON_REMOVE "minus"
+#define UI_ICON_REFRESH "arrow.clockwise"
+#define UI_ICON_UPLOAD "square.and.arrow.up"
+#define UI_ICON_SAVE_LOCAL "square.and.arrow.down"
+#define UI_ICON_EDIT_COPY "document.on.document"
+#define UI_ICON_EDIT_CUT "scissors"
+#define UI_ICON_EDIT_DELETE "minus.circle"
+#define UI_ICON_EDIT_PASTE "document.on.clipboard"
+#define UI_ICON_UNDO "arrow.uturn.backward"
+#define UI_ICON_REDO "arrow.uturn.forward"
+#define UI_ICON_SIDEBAR_LEFT "sidebar.left"
+#define UI_ICON_SIDEBAR_RIGHT "sidebar.right"
+#define UI_ICON_GO_BACK "chevron.left"
+#define UI_ICON_GO_FORWARD "chevron.right"
+#define UI_ICON_GO_UP "chevron.up"
+#define UI_ICON_GO_DOWN "chevron.down"
+#define UI_ICON_VIEW_LIST "list.bullet"
+#define UI_ICON_VIEW_GRID "square.grid.2x2"
+#define UI_ICON_VIEW_DUAL "rectangle.split.2x1"
+#define UI_ICON_VIEW_FULLSCREEN "arrow.up.left.and.arrow.down.right.rectangle"
+#define UI_ICON_VIEW_RESTORE "arrow.down.forward.and.arrow.up.backward.rectangle"
+#define UI_ICON_TEXT_BOLD "bold"
+#define UI_ICON_TEXT_ITALIC "italic"
+#define UI_ICON_TEXT_UNDERLINE "underline"
+#define UI_ICON_LIST_BULLET "list.bullet"
+#define UI_ICON_LIST_ORDERED "list.number"
+#define UI_ICON_LIST_CHECK "checklist"
+#define UI_ICON_CHECKBOX "checkmark.square"
+#define UI_ICON_STAR "star"
+#define UI_ICON_VIEW_REVEAL "eye"
+#define UI_ICON_VIEW_CONCEAL "eye.slash"
+#define UI_ICON_SETTINGS "gearshape"
+#define UI_ICON_MEDIA_PLAY "play.fill"
+#define UI_ICON_MEDIA_STOP "stop.fill"
+#define UI_ICON_MEDIA_PAUSE "pause.fill"
+#define UI_ICON_MEDIA_SEEK_BACKWARD "backward.fill"
+#define UI_ICON_MEDIA_SEEK_FORWARD "forward.fill"
+#define UI_ICON_MEDIA_SKIP_BACKWARD "backward.end.fill"
+#define UI_ICON_MEDIA_SKIP_FORWARD "forward.end.fill"
+#define UI_ICON_CALL_START "phone"
+#define UI_ICON_CALL_STOP "phone.down"
+#define UI_ICON_CALL_INCOMING "phone.arrow.down.left"
+#define UI_ICON_CALL_OUTGOING "phone.arrow.up.right"
+#define UI_ICON_MICROPHONE_ON "microphone"
+#define UI_ICON_MICROPHONE_OFF "microphone.slash"
+#define UI_ICON_LOCKED "lock"
+#define UI_ICON_UNLOCKED "lock.open"
+#define UI_ICON_SECURE "lock"
+#define UI_ICON_INSECURE "lock.trianglebadge.exclamationmark"
+
+#endif /* UI_COCOA */
+    
+#ifdef UI_MOTIF
+    
+#define UI_ICON_HOME ""
+#define UI_ICON_NEW_WINDOW ""
+#define UI_ICON_NEW_TAB ""
+#define UI_ICON_NEW_FOLDER ""
+#define UI_ICON_NEW_DOCUMENT ""
+#define UI_ICON_NEW_APPOINTMENT ""
+#define UI_ICON_NEW_CHAT_MESSAGE ""
+#define UI_ICON_NEW_CONTACT ""
+#define UI_ICON_NEW_MAIL ""
+#define UI_ICON_ADD_BOOKMARK ""
+#define UI_ICON_ADD_IMAGE ""
+#define UI_ICON_ADD_LINK ""
+#define UI_ICON_ADD_TEXT ""
+#define UI_ICON_ADD ""
+#define UI_ICON_REMOVE ""
+#define UI_ICON_REFRESH ""
+#define UI_ICON_UPLOAD ""
+#define UI_ICON_SAVE_LOCAL ""
+#define UI_ICON_EDIT_COPY ""
+#define UI_ICON_EDIT_CUT ""
+#define UI_ICON_EDIT_DELETE ""
+#define UI_ICON_EDIT_PASTE ""
+#define UI_ICON_UNDO ""
+#define UI_ICON_REDO ""
+#define UI_ICON_SIDEBAR_LEFT ""
+#define UI_ICON_SIDEBAR_RIGHT ""
+#define UI_ICON_GO_BACK ""
+#define UI_ICON_GO_FORWARD ""
+#define UI_ICON_GO_UP ""
+#define UI_ICON_GO_DOWN ""
+#define UI_ICON_VIEW_LIST ""
+#define UI_ICON_VIEW_GRID ""
+#define UI_ICON_VIEW_DUAL ""
+#define UI_ICON_VIEW_FULLSCREEN ""
+#define UI_ICON_VIEW_RESTORE ""
+#define UI_ICON_TEXT_BOLD ""
+#define UI_ICON_TEXT_ITALIC ""
+#define UI_ICON_TEXT_UNDERLINE ""
+#define UI_ICON_LIST_BULLET ""
+#define UI_ICON_LIST_ORDERED ""
+#define UI_ICON_LIST_CHECK ""
+#define UI_ICON_CHECKBOX ""
+#define UI_ICON_STAR ""
+#define UI_ICON_VIEW_REVEAL ""
+#define UI_ICON_VIEW_CONCEAL ""
+#define UI_ICON_SETTINGS ""
+#define UI_ICON_MEDIA_PLAY ""
+#define UI_ICON_MEDIA_STOP ""
+#define UI_ICON_MEDIA_PAUSE ""
+#define UI_ICON_MEDIA_SEEK_BACKWARD ""
+#define UI_ICON_MEDIA_SEEK_FORWARD ""
+#define UI_ICON_MEDIA_SKIP_BACKWARD ""
+#define UI_ICON_MEDIA_SKIP_FORWARD ""
+#define UI_ICON_CALL_START ""
+#define UI_ICON_CALL_STOP ""
+#define UI_ICON_CALL_INCOMING ""
+#define UI_ICON_CALL_OUTGOING ""
+#define UI_ICON_MICROPHONE_ON ""
+#define UI_ICON_MICROPHONE_OFF ""
+#define UI_ICON_LOCKED ""
+#define UI_ICON_UNLOCKED ""
+#define UI_ICON_SECURE ""
+#define UI_ICON_INSECURE ""
     
+#endif /* UI_MOTIF */
+    
+#ifdef UI_WIN32
+    
+#define UI_ICON_HOME ""
+#define UI_ICON_NEW_WINDOW ""
+#define UI_ICON_NEW_TAB ""
+#define UI_ICON_NEW_FOLDER ""
+#define UI_ICON_NEW_DOCUMENT ""
+#define UI_ICON_NEW_APPOINTMENT ""
+#define UI_ICON_NEW_CHAT_MESSAGE ""
+#define UI_ICON_NEW_CONTACT ""
+#define UI_ICON_NEW_MAIL ""
+#define UI_ICON_ADD_BOOKMARK ""
+#define UI_ICON_ADD_IMAGE ""
+#define UI_ICON_ADD_LINK ""
+#define UI_ICON_ADD_TEXT ""
+#define UI_ICON_ADD ""
+#define UI_ICON_REMOVE ""
+#define UI_ICON_REFRESH ""
+#define UI_ICON_UPLOAD ""
+#define UI_ICON_SAVE_LOCAL ""
+#define UI_ICON_EDIT_COPY ""
+#define UI_ICON_EDIT_CUT ""
+#define UI_ICON_EDIT_DELETE ""
+#define UI_ICON_EDIT_PASTE ""
+#define UI_ICON_UNDO ""
+#define UI_ICON_REDO ""
+#define UI_ICON_SIDEBAR_LEFT ""
+#define UI_ICON_SIDEBAR_RIGHT ""
+#define UI_ICON_GO_BACK ""
+#define UI_ICON_GO_FORWARD ""
+#define UI_ICON_GO_UP ""
+#define UI_ICON_GO_DOWN ""
+#define UI_ICON_VIEW_LIST ""
+#define UI_ICON_VIEW_GRID ""
+#define UI_ICON_VIEW_DUAL ""
+#define UI_ICON_VIEW_FULLSCREEN ""
+#define UI_ICON_VIEW_RESTORE ""
+#define UI_ICON_TEXT_BOLD ""
+#define UI_ICON_TEXT_ITALIC ""
+#define UI_ICON_TEXT_UNDERLINE ""
+#define UI_ICON_LIST_BULLET ""
+#define UI_ICON_LIST_ORDERED ""
+#define UI_ICON_LIST_CHECK ""
+#define UI_ICON_CHECKBOX ""
+#define UI_ICON_STAR ""
+#define UI_ICON_VIEW_REVEAL ""
+#define UI_ICON_VIEW_CONCEAL ""
+#define UI_ICON_SETTINGS ""
+#define UI_ICON_MEDIA_PLAY ""
+#define UI_ICON_MEDIA_STOP ""
+#define UI_ICON_MEDIA_PAUSE ""
+#define UI_ICON_MEDIA_SEEK_BACKWARD ""
+#define UI_ICON_MEDIA_SEEK_FORWARD ""
+#define UI_ICON_MEDIA_SKIP_BACKWARD ""
+#define UI_ICON_MEDIA_SKIP_FORWARD ""
+#define UI_ICON_CALL_START ""
+#define UI_ICON_CALL_STOP ""
+#define UI_ICON_CALL_INCOMING ""
+#define UI_ICON_CALL_OUTGOING ""
+#define UI_ICON_MICROPHONE_ON ""
+#define UI_ICON_MICROPHONE_OFF ""
+#define UI_ICON_LOCKED ""
+#define UI_ICON_UNLOCKED ""
+#define UI_ICON_SECURE ""
+#define UI_ICON_INSECURE ""
+    
+#endif /* UI_MOTIF */
+    
+    
+enum UiIconId {
+    UI_ICON_ID_HOME,
+    UI_ICON_ID_NEW_WINDOW,
+    UI_ICON_ID_NEW_TAB,
+    UI_ICON_ID_NEW_FOLDER,
+    UI_ICON_ID_NEW_DOCUMENT,
+    UI_ICON_ID_NEW_APPOINTMENT,
+    UI_ICON_ID_NEW_CHAT_MESSAGE,
+    UI_ICON_ID_NEW_CONTACT,
+    UI_ICON_ID_NEW_MAIL,
+    UI_ICON_ID_ADD_BOOKMARK,
+    UI_ICON_ID_ADD_IMAGE,
+    UI_ICON_ID_ADD_LINK,
+    UI_ICON_ID_ADD_TEXT,
+    UI_ICON_ID_ADD,
+    UI_ICON_ID_REMOVE,
+    UI_ICON_ID_REFRESH,
+    UI_ICON_ID_UPLOAD,
+    UI_ICON_ID_SAVE_LOCAL,
+    UI_ICON_ID_EDIT_COPY,
+    UI_ICON_ID_EDIT_CUT,
+    UI_ICON_ID_EDIT_DELETE,
+    UI_ICON_ID_EDIT_PASTE,
+    UI_ICON_ID_UNDO,
+    UI_ICON_ID_REDO,
+    UI_ICON_ID_SIDEBAR_LEFT,
+    UI_ICON_ID_SIDEBAR_RIGHT,
+    UI_ICON_ID_GO_BACK,
+    UI_ICON_ID_GO_FORWARD,
+    UI_ICON_ID_GO_UP,
+    UI_ICON_ID_GO_DOWN,
+    UI_ICON_ID_VIEW_LIST,
+    UI_ICON_ID_VIEW_GRID,
+    UI_ICON_ID_VIEW_DUAL,
+    UI_ICON_ID_VIEW_FULLSCREEN,
+    UI_ICON_ID_VIEW_RESTORE,
+    UI_ICON_ID_TEXT_BOLD,
+    UI_ICON_ID_TEXT_ITALIC,
+    UI_ICON_ID_TEXT_UNDERLINE,
+    UI_ICON_ID_LIST_BULLET,
+    UI_ICON_ID_LIST_ORDERED,
+    UI_ICON_ID_LIST_CHECK,
+    UI_ICON_ID_CHECKBOX,
+    UI_ICON_ID_STAR,
+    UI_ICON_ID_VIEW_REVEAL,
+    UI_ICON_ID_VIEW_CONCEAL,
+    UI_ICON_ID_SETTINGS,
+    UI_ICON_ID_MEDIA_PLAY,
+    UI_ICON_ID_MEDIA_STOP,
+    UI_ICON_ID_MEDIA_PAUSE,
+    UI_ICON_ID_MEDIA_SEEK_BACKWARD,
+    UI_ICON_ID_MEDIA_SEEK_FORWARD,
+    UI_ICON_ID_MEDIA_SKIP_BACKWARD,
+    UI_ICON_ID_MEDIA_SKIP_FORWARD,
+    UI_ICON_ID_CALL_START,
+    UI_ICON_ID_CALL_STOP,
+    UI_ICON_ID_CALL_INCOMING,
+    UI_ICON_ID_CALL_OUTGOING,
+    UI_ICON_ID_MICROPHONE_ON,
+    UI_ICON_ID_MICROPHONE_OFF,
+    UI_ICON_ID_LOCKED,
+    UI_ICON_ID_UNLOCKED,
+    UI_ICON_ID_SECURE,
+    UI_ICON_ID_INSECURE
+};
     
 UIEXPORT UiIcon* ui_icon(const char* name, size_t size);
 UIEXPORT UiIcon* ui_icon_unscaled(const char *name, int size);
@@ -85,6 +472,8 @@ UIEXPORT UiIcon* ui_foldericon(size_t size);
 UIEXPORT UiIcon* ui_fileicon(size_t size);
 
 
+UIEXPORT const char* ui_icon_name(enum UiIconId icon_id);
+
 #ifdef __cplusplus
 }
 #endif
index 06fe345396dfdc53e463982053c7c811585e60b7..35de753c60a999004adbab48655f055e0e1f09e9 100644 (file)
@@ -166,14 +166,19 @@ struct UiListArgs {
     void *getstyledata;
     ui_callback onactivate;
     void *onactivatedata;
+    const char *onactivate_action;
     ui_callback onselection;
     void *onselectiondata;
+    const char *onselection_action;
     ui_callback ondragstart;
     void *ondragstartdata;
+    const char *ondragstart_action;
     ui_callback ondragcomplete;
     void *ondragcompletedata;
+    const char *ondragcomplete_action;
     ui_callback ondrop;
     void *ondropdata;
+    const char *ondrop_action;
     UiBool multiselection;
     UiBool hide_header;
     UiMenuBuilder *contextmenu;
index bd5b96b6a5d320ebe88263255808af01eaf378df..5ad8776419ddbc73c3c44794dd9faaa799efb264 100644 (file)
@@ -39,7 +39,7 @@ extern "C" {
 typedef struct UiMenuItemArgs {
        const char *label;
        const char *icon;
-
+        
        ui_callback onclick;
        void *onclickdata;
         const char *action;
@@ -66,6 +66,8 @@ typedef struct UiMenuToggleItemArgs {
 typedef struct UiMenuItemListArgs {
        const char *varname;
        ui_getvaluefunc getvalue;
+        ui_getvaluefunc2 getvalue2;
+        void *getvaluedata;
        ui_callback onselect;
        void *onselectdata;
         const char *action;
index ebea880d84bc0c4c7df1b75155cf8dd27df593dc..793d8eed1b902bc58456a8a9754a593717853fae 100644 (file)
@@ -58,10 +58,27 @@ typedef struct UiTextAreaArgs {
     const char *varname;
     ui_callback onchange;
     void *onchangedata;
+    const char *onchange_action;
+    ui_callback ontextchanged;
+    void *ontextchangeddata;
+    const char *ontextchanged_action;
     
     const int *states;
     const int *visibility_states;
 } UiTextAreaArgs;
+
+typedef enum UiTextChangedEventType {
+    UI_TEXT_INSERT = 0,
+    UI_TEXT_DELETE
+} UiTextChangedEventType;
+
+typedef struct UiTextChangeEventData {
+    UiTextChangedEventType type;
+    int begin;
+    int end;
+    const char *text;
+    int length;
+} UiTextChangeEventData;
     
 typedef struct UiTextFieldArgs {
     UiBool fill;
@@ -87,6 +104,8 @@ typedef struct UiTextFieldArgs {
     void *onchangedata;
     ui_callback onactivate;
     void *onactivatedata;
+    const char *onactivate_action;
+    const char *onchange_action;
     
     const int *states;
     const int *visibility_states;
@@ -129,6 +148,7 @@ typedef struct UiPathTextFieldArgs {
 
     ui_callback onactivate;
     void *onactivatedata;
+    const char *action;
     
     ui_callback ondragstart;
     void *ondragstartdata;
@@ -149,6 +169,13 @@ UIEXPORT UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea);
 UIEXPORT void ui_text_undo(UiText *value);
 UIEXPORT void ui_text_redo(UiText *value);
 
+UIEXPORT void ui_textarea_focus(UIWIDGET textarea);
+UIEXPORT void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end);
+UIEXPORT void ui_textarea_select_all(UIWIDGET textarea);
+UIEXPORT void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable);
+UIEXPORT UiBool ui_textarea_is_editable(UIWIDGET textarea);
+UIEXPORT void ui_textarea_set_position(UIWIDGET textarea, int pos);
+UIEXPORT int ui_textarea_get_position(UIWIDGET textarea);
 UIEXPORT void ui_textarea_scroll_to(UIWIDGET textarea, int pos);
 
 #define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
index 29319ecb9172235af0e7e7b2722e8bedb8c40c94..d52523123cf83bc732e197c999b1c37d939a4b1c 100644 (file)
@@ -67,6 +67,28 @@ typedef struct UiToolbarToggleItemArgs {
     const int *visibility_states;
 } UiToolbarToggleItemArgs;
 
+typedef struct UiToolbarContentToggleItemArgs {
+    const char *label0;
+    const char *icon0;
+    const char *tooltip0;
+    const char *label1;
+    const char *icon1;
+    const char *tooltip1;
+
+    const char *varname;
+    ui_callback onchange;
+    void *onchangedata;
+    const char *action;
+    const char *accelerator;
+    const char *accelerator_text;
+    
+    int toggled_by_state;
+    UiBool istogglebutton;
+
+    const int *states;
+    const int *visibility_states;
+} UiToolbarContentToggleItemArgs;
+
 typedef struct UiToolbarMenuArgs {
     const char *label;
     const char *icon;
@@ -87,6 +109,7 @@ enum UiToolbarPos {
 
 #define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, &(UiToolbarItemArgs){ __VA_ARGS__ } )
 #define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } )
+#define ui_toolbar_content_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } )
 
 #define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, &(UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close())
 #define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, &(UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close())
@@ -94,6 +117,7 @@ enum UiToolbarPos {
 
 UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args);
 UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args);
+UIEXPORT void ui_toolbar_content_toggleitem_create(const char* name, UiToolbarContentToggleItemArgs *args);
 UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args);
 
 UIEXPORT void ui_toolbar_add_default(const char *name, enum UiToolbarPos pos);
index b798e664b7d53699edf528a3e38b9c2b9ff32d63..0537d58f073ec029fe8ad69f73d2d28025bab62a 100644 (file)
@@ -47,6 +47,7 @@ typedef void* UIMENU;   // NSMenu*
 
 #include <gtk/gtk.h>
 #define UIWIDGET GtkWidget*
+#define UIWINDOW void*
 
 #if UI_GTK2 || UI_GTK3
 #define UIMENU   GtkMenu*
@@ -83,6 +84,7 @@ typedef void* UIMENU;   // NSMenu*
 
 #include <Xm/XmAll.h> 
 #define UIWIDGET Widget
+#define UIWINDOW void*
 #define UIMENU   Widget
 
 
@@ -154,6 +156,13 @@ typedef struct UiWidget UiWidget;
 #define UIWINDOW UiWidget*
 #define UIMENU   void*
 
+#else
+
+#define UI_GENERIC
+#define UIWIDGET void*
+#define UIWINDOW void*
+#define UIMENU   void*
+
 #endif
 
 #ifndef TRUE
@@ -171,9 +180,9 @@ typedef struct UiWidget UiWidget;
 extern "C" {
 #endif
 
-#define UI_GROUP_SELECTION  20000
+#define UI_STATE_SELECTION  20000
 
-#define UI_GROUPS(...) (const int[]){ __VA_ARGS__, -1 }
+#define UI_STATES(...) (const int[]){ __VA_ARGS__, -1 }
     
 /* public types */
 #ifndef __cplusplus
@@ -183,7 +192,6 @@ typedef bool UiBool;
 #endif
 
 typedef struct UiObject     UiObject;
-typedef struct UiContainerX UiContainerX;
 typedef struct UiEvent      UiEvent;
 typedef struct UiMouseEvent UiMouseEvent;
 typedef struct UiObserver   UiObserver;
@@ -205,6 +213,8 @@ typedef struct UiListSelection UiListSelection;
 typedef struct UiTextStyle  UiTextStyle;
 typedef struct UiColor      UiColor;
 
+typedef enum UiEventType UiEventType;
+
 /* begin opaque types */
 typedef struct UiContext     UiContext;
 typedef struct UiContainer   UiContainer;
@@ -218,8 +228,6 @@ typedef struct UiDnD         UiDnD;
 typedef struct UiThreadpool  UiThreadpool;
 /* end opaque types */
 
-typedef struct UiTabbedPane UiTabbedPane;
-
 typedef enum UiTri {
     UI_DEFAULT = 0,
     UI_ON,
@@ -273,12 +281,10 @@ struct UiObject {
      */
     UIWIDGET    widget;
 
-#if defined(UI_COCOA) || defined(UI_WINUI)
     /*
      * native window object 
      */
     UIWINDOW    wobj;
-#endif
     
     /*
      * user window data
@@ -292,15 +298,15 @@ struct UiObject {
     
     /*
      * container list
-     * TODO: remove old UiContainer and rename UiContainerX to UiContainer
      */
-    UiContainerX *container_begin;
-    UiContainerX *container_end;
+    UiContainer *container_begin;
+    UiContainer *container_end;
     
     /*
-     * next container object
+     * called when someone requests to close the window
      */
-    UiObject    *next;
+    void (*onclose)(UiEvent *event, void *userdata);
+    void *onclosedata;
     
     /*
      * obj destroy func
@@ -313,31 +319,32 @@ struct UiObject {
     unsigned int ref;
 };
 
-struct UiTabbedPane {
-    /*
-     * native widget
-     */
-    UIWIDGET  widget;
-    
-    /*
-     * current document
-     */
-    void      *document;
-    
-    /*
-     * parent context
-     */
-    UiContext *ctx;
+enum UiEventType {
+    UI_EVENT_DATA_NULL = 0,
+    UI_EVENT_DATA_POINTER,
+    UI_EVENT_DATA_STRING,
+    UI_EVENT_DATA_INTEGER_VALUE,
+    UI_EVENT_DATA_STRING_VALUE,
+    UI_EVENT_DATA_TEXT_VALUE,
+    UI_EVENT_DATA_DOUBLE_VALUE,
+    UI_EVENT_DATA_RANGE_VALUE,
+    UI_EVENT_DATA_TEXT_CHANGED,
+    UI_EVENT_DATA_LIST_SELECTION,
+    UI_EVENT_DATA_LIST_ELM,
+    UI_EVENT_DATA_DND,
+    UI_EVENT_DATA_SUBLIST,
+    UI_EVENT_DATA_FILE_LIST,
+    UI_EVENT_DATA_TYPED_OBJECT
 };
 
 struct UiEvent {
-    UiObject *obj;
-    void     *document;
-    void     *window;
-    void     *eventdata;
-    int      eventdatatype;
-    int      intval;
-    int      set;
+    UiObject     *obj;
+    void         *document;
+    void         *window;
+    void         *eventdata;
+    UiEventType  eventdatatype;
+    int          intval;
+    int          set;
 };
 
 struct UiMouseEvent {
@@ -401,13 +408,14 @@ struct UiText {
     void  (*selection)(UiText*, int*, int*); /* text, begin, end */
     int   (*length)(UiText*);
     void  (*remove)(UiText*, int, int); /* text, begin, end */
+    void  (*setreadonly)(UiText*, int);
     UiStr value;
     int   pos;
+    int   readonly;
     void  *obj;
     int   datatype;
     void  *data1;
     void  *data2;
-    // TODO: replacefunc, ...
     UiObserver *observers;
 };
 
@@ -433,27 +441,33 @@ typedef void (*ui_list_destroy_func)(UiContext *ctx, UiList *list, void *userdat
  * abstract list
  */
 struct UiList {
-    /* get the first element */
+    // destructor
+    ui_list_destroy_func destroy;
+    // get the first element
     void*(*first)(UiList *list);
-    /* get the next element */
+    // get the next element
     void*(*next)(UiList *list);
-    /* get the nth element */
+    // get the nth element
     void*(*get)(UiList *list, int i);
-    /* get the number of elements */
+    // get the number of elements 
     int(*count)(UiList *list);
-    /* iterator changes after first() next() and get() */
+    // iterator changes after first() next() and get() 
     void *iter;
-    /* private - implementation dependent */
+    // private - implementation dependent
     void *data;
     
-    /* binding functions */
+    // binding functions 
     void (*update)(UiList *list, int i);
     UiListSelection (*getselection)(UiList *list);
     void (*setselection)(UiList *list, UiListSelection selection);
-    /* binding object */
+    // binding object
     void *obj;
+    // saved selection after unbind
+    UiListSelection *saved_selection;
+    // enable selection saving
+    UiBool save_selection;
     
-    /* list of observers */
+    // list of observers
     UiObserver *observers;
 };
 
@@ -494,21 +508,11 @@ typedef struct UiCondVar {
     int intdata;
 } UiCondVar;
 
-enum UiEventType {
-    UI_EVENT_DATA_NULL = 0,
-    UI_EVENT_DATA_POINTER,
-    UI_EVENT_DATA_STRING,
-    UI_EVENT_DATA_INTEGER_VALUE,
-    UI_EVENT_DATA_STRING_VALUE,
-    UI_EVENT_DATA_TEXT_VALUE,
-    UI_EVENT_DATA_DOUBLE_VALUE,
-    UI_EVENT_DATA_RANGE_VALUE,
-    UI_EVENT_DATA_LIST_SELECTION,
-    UI_EVENT_DATA_LIST_ELM,
-    UI_EVENT_DATA_DND,
-    UI_EVENT_DATA_SUBLIST,
-    UI_EVENT_DATA_FILE_LIST
-};
+// eventdata in case eventdatatype is UI_EVENT_DATA_TYPED_OBJECT
+typedef struct UiTypedObj {
+    void *ptr;
+    uint64_t type;
+} UiTypedObj;
 
 #define UI_COLOR(r, g, b) (UiColor){r, g, b}
 struct UiColor {
@@ -529,7 +533,7 @@ struct UiTextStyle {
 
 
 UIEXPORT void ui_init(const char *appname, int argc, char **argv);
-UIEXPORT const char* ui_appname();
+UIEXPORT const char* ui_appname(void);
 
 UIEXPORT void ui_add_styledata(const char *styledata, int len);
 
@@ -537,17 +541,19 @@ UIEXPORT UiContext* ui_global_context(void);
 
 UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata);
 
-UIEXPORT void ui_context_destroy(UiContext *ctx);
-
 UIEXPORT UiContext* ui_context_parent(UiContext *ctx);
+UIEXPORT UiContext* ui_context_toplevel_parent(UiContext *ctx);
 
 UIEXPORT void ui_object_ref(UiObject *obj);
 UIEXPORT int ui_object_unref(UiObject *obj);
 
 UIEXPORT void ui_onstartup(ui_callback f, void *userdata);
+UIEXPORT void ui_onnewwindow(ui_callback f, void *userdata);
 UIEXPORT void ui_onopen(ui_callback f, void *userdata);
 UIEXPORT void ui_onexit(ui_callback f, void *userdata);
 
+UIEXPORT void ui_newwindow(void);
+
 UIEXPORT int ui_app_save_settings(void);
 UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
 
@@ -570,11 +576,22 @@ UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool);
 UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd);
 
 UIEXPORT void* ui_document_new(size_t size);
+UIEXPORT void  ui_document_ref(void *doc);
+UIEXPORT void  ui_document_unref(void *doc);
 UIEXPORT void  ui_document_destroy(void *doc);
+UIEXPORT void  ui_document_onattach(void *doc, ui_callback cb, void *data);
+UIEXPORT void  ui_document_ondetach(void *doc, ui_callback cb, void *data);
+UIEXPORT void  ui_document_onattachmentstatuschange(void *doc, ui_callback cb, void *data);
+UIEXPORT void  ui_document_onattach_action(void *doc, const char *action);
+UIEXPORT void  ui_document_ondetach_action(void *doc, const char *action);
+UIEXPORT void  ui_document_onattachmentstatuschange_action(void *doc, const char *action);
 
-UIEXPORT void* ui_get_subdocument(void *document);               // deprecated
+UIEXPORT int   ui_document_is_attached(void *doc);
+UIEXPORT int   ui_document_is_attached_to_obj(void *doc);
 
 UIEXPORT UiContext* ui_document_context(void *doc);
+UIEXPORT void* ui_context_document(UiContext *ctx);
+UIEXPORT UiObject* ui_context_obj(UiContext *ctx);
 
 UIEXPORT void* ui_context_get_document(UiContext *ctx);
 UIEXPORT void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable);
@@ -585,8 +602,30 @@ UIEXPORT void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefun
 UIEXPORT void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates);
 UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates);
 
+UIEXPORT void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata);
+UIEXPORT void ui_add_action_with_accelerator(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text);
+UIEXPORT void ui_update_action_bindings(UiContext *ctx);
+UIEXPORT int ui_call_action(UiContext *ctx, const char *action_name);
+UIEXPORT int ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval);
+UIEXPORT int ui_call_action3(UiContext *ctx, const char *action_name, void *ptr, uint64_t type_id);
+UIEXPORT void ui_broadcast_action(const char *action_name);
+UIEXPORT void ui_broadcast_action2(const char *action_name, void *eventdata, int intval);
+UIEXPORT void ui_broadcast_action3(const char *action_name, void *ptr, uint64_t type_id);
+UIEXPORT void ui_mainthread_broadcast(const char *action_name);
+UIEXPORT void ui_mainthread_broadcast2(const char *action_name, void *eventdata, int intval);
+UIEXPORT void ui_mainthread_broadcast3(const char *action_name, void *ptr, uint64_t type_id);
+UIEXPORT void ui_call_action_on(UiContext *ctx, const char *action);
+
 UIEXPORT void ui_set_state(UiContext *ctx, int state);
 UIEXPORT void ui_unset_state(UiContext *ctx, int state);
+UIEXPORT void ui_suppress_state(UiContext *ctx, int state);
+UIEXPORT void ui_unsuppress_state(UiContext *ctx, int state);
 UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates);
     
 UIEXPORT void* ui_allocator(UiContext *ctx);
@@ -598,6 +637,7 @@ UIEXPORT void  ui_free(UiContext *ctx, void *ptr);
 UIEXPORT void* ui_realloc(UiContext *ctx, void *ptr, size_t size);
 UIEXPORT char* ui_strdup(UiContext *ctx, const char *str);
 UIEXPORT void  ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr);
+UIEXPORT void  ui_remove_destructor(UiContext *ctx, void *data);
 UIEXPORT void  ui_set_destructor(void *mem, ui_destructor_func destr);
 
 // types
@@ -680,6 +720,7 @@ UIEXPORT void* ui_list_get(UiList *list, int i);
 UIEXPORT int ui_list_count(UiList *list);
 UIEXPORT void ui_list_append(UiList *list, void *data);
 UIEXPORT void ui_list_prepend(UiList *list, void *data);
+UIEXPORT void ui_list_insert(UiList *list, int index, void *data);
 UIEXPORT void ui_list_remove(UiList *list, int i);
 UIEXPORT void ui_list_clear(UiList *list);
 UIEXPORT void ui_list_update(UiList *list);
@@ -688,6 +729,7 @@ UIEXPORT UiListSelection ui_list_get_selection(UiList *list);
 UIEXPORT void ui_list_set_selection(UiList *list, UiListSelection sel);
 UIEXPORT void ui_list_addobsv(UiList *list, ui_callback f, void *data);
 UIEXPORT void ui_list_notify(UiList *list);
+UIEXPORT void ui_list_clear_saved_selection(UiList *list);
 
 UIEXPORT int ui_list_getselection(UiList *list);
 UIEXPORT void ui_list_setselection(UiList *list, int index);
@@ -703,7 +745,17 @@ UIEXPORT char* ui_clipboard_get();
 
 UIEXPORT void ui_add_image(char *imgname, char *filename); // TODO: remove?
 
-
+UIEXPORT char* ui_text_getsubstr(UiText *text, int begin, int end);
+UIEXPORT void  ui_text_insert(UiText *text, int pos, const char *str);
+UIEXPORT void  ui_text_replace(UiText *text, int begin, int end, const char *str);
+UIEXPORT void  ui_text_setposition(UiText *text, int pos);
+UIEXPORT int   ui_text_position(UiText *text);
+UIEXPORT void  ui_text_showposition(UiText *text, int pos);
+UIEXPORT void  ui_text_setselection(UiText *text, int begin, int end);
+UIEXPORT void  ui_text_selection(UiText *text, int *begin, int *end);
+UIEXPORT int   ui_text_length(UiText *text);
+UIEXPORT void  ui_text_remove(UiText *text, int begin, int end);
+UIEXPORT void  ui_text_setreadonly(UiText *text, int readonly);
 
 UIEXPORT UiStr ui_str(char *cstr);
 UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v));
@@ -728,6 +780,7 @@ UIEXPORT UiBool ui_selection_events_is_enabled(void);
     
 UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata);
 UIEXPORT void ui_global_list_destructor(ui_list_destroy_func func, void *userdata);
+UIEXPORT void ui_list_class_set_destructor(UiList *list, ui_list_destroy_func destroy);
 UIEXPORT void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list));
 UIEXPORT void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list));
 UIEXPORT void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i));
@@ -741,6 +794,8 @@ UIEXPORT void* ui_object_get(UiObject *obj, const char *key);
 UIEXPORT void ui_app_ref(void);
 UIEXPORT void ui_app_unref(void);
 
+UIEXPORT void ui_open_uri(const char *uri);
+
 #ifdef __cplusplus
 }
 #endif
index 40503baa2fb88e61111eced55a096b768f5a4bc5..62c5c6341d6e9f65008a080826f9e7a0e12c4757 100644 (file)
@@ -52,6 +52,8 @@ typedef struct UiWidgetArgs {
     const char *style_class;
 } UiWidgetArgs;
 
+#ifndef UI_GENERIC
+
 #ifdef UI_GTK
 typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_QT)
@@ -71,6 +73,7 @@ UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func cre
 
 #define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, &(UiWidgetArgs) { __VA_ARGS__ })
 
+#endif
 
 UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);