]> uap-core.de Git - mizunara.git/commitdiff
move navigation to the headerbar master
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 12 Dec 2025 09:37:38 +0000 (10:37 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 12 Dec 2025 09:37:38 +0000 (10:37 +0100)
60 files changed:
mizunara/menu.c
mizunara/window.c
ui/common/app.c [new file with mode: 0644]
ui/common/app.h [new file with mode: 0644]
ui/common/args.c
ui/common/args.h
ui/common/context.c
ui/common/context.h
ui/common/menu.c
ui/common/menu.h
ui/common/message.c [new file with mode: 0644]
ui/common/message.h [new file with mode: 0644]
ui/common/object.c
ui/common/object.h
ui/common/objs.mk
ui/common/properties.c
ui/common/threadpool.c
ui/common/threadpool.h
ui/common/toolbar.c
ui/common/toolbar.h
ui/common/types.c
ui/common/types.h
ui/common/utils.c [new file with mode: 0644]
ui/common/utils.h [new file with mode: 0644]
ui/common/wrapper.c
ui/common/wrapper.h
ui/gtk/button.c
ui/gtk/container.c
ui/gtk/container.h
ui/gtk/entry.c
ui/gtk/graphics.c
ui/gtk/headerbar.c
ui/gtk/headerbar.h
ui/gtk/image.c
ui/gtk/list.c
ui/gtk/list.h
ui/gtk/menu.c
ui/gtk/text.c
ui/gtk/toolbar.c
ui/gtk/toolkit.c
ui/gtk/toolkit.h
ui/gtk/webview.c
ui/gtk/widget.c
ui/gtk/widget.h
ui/gtk/window.c
ui/ui/button.h
ui/ui/container.h
ui/ui/entry.h
ui/ui/image.h
ui/ui/list.h [moved from ui/ui/tree.h with 85% similarity]
ui/ui/menu.h
ui/ui/stock.h [deleted file]
ui/ui/text.h
ui/ui/toolbar.h
ui/ui/toolkit.h
ui/ui/ui.h
ui/ui/webview.h
ui/ui/widget.h
ui/ui/win32.h
ui/ui/window.h

index 461ac89eef66c5ae84503eaa8159f26fdeb24262..1014f84064d985b1b89dc8c07f141c6391a4f9ca 100644 (file)
@@ -52,9 +52,16 @@ static void menubar_init(void) {
 }
 
 static void toolbar_init(void) {
+    ui_toolbar_item("Back", .icon = UI_ICON_GO_BACK);
+    ui_toolbar_item("Forward", .icon = UI_ICON_GO_FORWARD);
     ui_toolbar_item("Home", .icon = UI_ICON_HOME, .onclick = action_go_home);
-    
+#ifdef UI_LIBADWAITA
+    ui_toolbar_add_default("Back", UI_TOOLBAR_LEFT);
+    ui_toolbar_add_default("Forward", UI_TOOLBAR_LEFT);
+    ui_toolbar_add_default("Home", UI_TOOLBAR_RIGHT);
+#else
     ui_toolbar_add_default("Home", UI_TOOLBAR_LEFT);
+#endif
 }
 
 static void appmenu_init(void) {
index d3edb43568161c28de583be1f94145d6dbe874ee..412e5752dfdb7df5d9b60ab7db72b4722f5b1a3b 100644 (file)
@@ -55,9 +55,17 @@ void window_update_gridview(
     mz_update_files_view((MzFilesView*)win->files_gridview, sections, numsections);
 }
 
+#ifdef UI_LIBADWAITA
+
+void libadwaita_headerbar_add() {
+    
+}
+
+#endif
+
 UiObject* window_create(const char *url) {
     // toplevel window object
-    UiObject *obj = ui_sidebar_window("Mizunara", NULL);
+    UiObject *obj = ui_sidebar_window("Mizunara");
     ui_window_size(obj, 1000, 600);
     
     // create window data object
@@ -89,11 +97,19 @@ UiObject* window_create(const char *url) {
                 .fill = TRUE);
     }
     
+#ifdef UI_LIBADWAITA
+    ui_headerbar(obj) {
+        ui_headerbar_center(obj) {
+            ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
+        }
+    }
+#else
     ui_hbox(obj, .spacing = 4, .margin_left = 6, .margin_right = 8) {
         ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_BACK);
         ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_FORWARD);
         ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
     }
+#endif
     
     window_create_browser_view(obj, wdata);
     ui_set(browser->view, 0); // select default view
diff --git a/ui/common/app.c b/ui/common/app.c
new file mode 100644 (file)
index 0000000..9674599
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "app.h"
+
+static ui_callback   startup_func;
+static void          *startup_data;
+static ui_callback   open_func;
+void                 *open_data;
+static ui_callback   exit_func;
+void                 *exit_data;
+
+
+void ui_onstartup(ui_callback f, void *userdata) {
+    startup_func = f;
+    startup_data = userdata;
+}
+
+void ui_onopen(ui_callback f, void *userdata) {
+    open_func = f;
+    open_data = userdata;
+}
+
+void ui_onexit(ui_callback f, void *userdata) {
+    exit_func = f;
+    exit_data = userdata;
+}
+
+
+void uic_application_startup(UiEvent *event) {
+    if(startup_func) {
+        startup_func(event, startup_data);
+    }
+}
+
+void uic_application_open(UiEvent *event) {
+    if(open_func) {
+        open_func(event, open_data);
+    }
+}
+
+void uic_application_exit(UiEvent *event) {
+    if(exit_func) {
+        exit_func(event, exit_data);
+    }
+}
diff --git a/ui/common/app.h b/ui/common/app.h
new file mode 100644 (file)
index 0000000..02356a9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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_APP_H
+#define UIC_APP_H
+
+#include "../ui/toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uic_application_startup(UiEvent *event);
+void uic_application_open(UiEvent *event);
+void uic_application_exit(UiEvent *event);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_APP_H */
+
index 796919ba834fd4797e69ff2935d0ca4c5cf1b770..2ef732e53afc72cc5ec6ff0874f680b62a9be367 100644 (file)
@@ -175,10 +175,10 @@ void ui_dialogwindow_args_free(UiDialogWindowArgs *args) {
     free((void*)args->lbutton2);
     free((void*)args->rbutton3);
     free((void*)args->rbutton4);
-    free((void*)args->lbutton1_groups);
-    free((void*)args->lbutton2_groups);
-    free((void*)args->rbutton3_groups);
-    free((void*)args->rbutton4_groups);
+    free((void*)args->lbutton1_states);
+    free((void*)args->lbutton2_states);
+    free((void*)args->rbutton3_states);
+    free((void*)args->rbutton4_states);
     free(args);
 }
 
@@ -310,16 +310,16 @@ void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclick
     args->onclickdata = onclickdata;
 }
 
-void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_toolbar_item_args_set_states(UiToolbarItemArgs *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_item_args_free(UiToolbarItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->tooltip);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -355,10 +355,10 @@ void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args,
     args->onchangedata = onchangedata;
 }
 
-void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args,int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *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_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
@@ -366,7 +366,7 @@ void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
     free((void*)args->icon);
     free((void*)args->tooltip);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -1383,10 +1383,10 @@ void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
     args->onclickdata = onclickdata;
 }
 
-void ui_button_args_set_groups(UiButtonArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+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));
+    ((int*)args->states)[numstates] = -1;
 }
 
 void ui_button_args_free(UiButtonArgs *args) {
@@ -1395,7 +1395,7 @@ void ui_button_args_free(UiButtonArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->tooltip);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -1502,14 +1502,14 @@ void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value) {
     args->value = value;
 }
 
-void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group) {
-    args->enable_group = group;
+void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state) {
+    args->enable_state = state;
 }
 
-void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_toggle_args_set_states(UiToggleArgs *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_toggle_args_free(UiToggleArgs *args) {
@@ -1519,7 +1519,7 @@ void ui_toggle_args_free(UiToggleArgs *args) {
     free((void*)args->icon);
     free((void*)args->tooltip);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -1633,10 +1633,10 @@ void ui_linkbutton_args_set_value(UiLinkButtonArgs *args, UiString *value) {
     args->value = value;
 }
 
-void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_linkbutton_args_set_states(UiLinkButtonArgs *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_linkbutton_args_free(UiLinkButtonArgs *args) {
@@ -1645,7 +1645,7 @@ void ui_linkbutton_args_free(UiLinkButtonArgs *args) {
     free((void*)args->label);
     free((void*)args->uri);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -1815,10 +1815,10 @@ void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder)
     args->contextmenu = menubuilder;
 }
 
-void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_list_args_set_states(UiListArgs *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_list_args_free(UiListArgs *args) {
@@ -1831,7 +1831,7 @@ void ui_list_args_free(UiListArgs *args) {
         }
         free(args->static_elements);
     }
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -1971,7 +1971,7 @@ void ui_sourcelist_args_free(UiSourceListArgs *args) {
     free((void*)args->style_class);
     free((void*)args->varname);
     free((void*)args->sublists);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -2071,17 +2071,17 @@ void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value) {
     args->value = value;
 }
 
-void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_textarea_args_set_states(UiTextAreaArgs *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_textarea_args_free(UiTextAreaArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -2191,17 +2191,17 @@ void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value) {
     args->value = value;
 }
 
-void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_textfield_args_set_states(UiTextFieldArgs *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_textfield_args_free(UiTextFieldArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -2314,17 +2314,17 @@ void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value) {
     args->rangevalue = value;
 }
 
-void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_spinbox_args_set_states(UiSpinBoxArgs *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_spinbox_args_free(UiSpinBoxArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
@@ -2414,17 +2414,17 @@ void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value) {
     args->value = value;
 }
 
-void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates) {
-    args->groups = calloc(numstates+1, sizeof(int));
-    memcpy((void*)args->groups, states, numstates * sizeof(int));
-    ((int*)args->groups)[numstates] = -1;
+void ui_webview_args_set_states(UiWebviewArgs *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_webview_args_free(UiWebviewArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
-    free((void*)args->groups);
+    free((void*)args->states);
     free(args);
 }
 
index e5331939787307de0ffbcebd317c7c88b1dcd6e2..41d33f6e4adfca0ff3938b57bf0127a1adc17747 100644 (file)
@@ -36,7 +36,7 @@
 #include "../ui/entry.h"
 #include "../ui/menu.h"
 #include "../ui/toolbar.h"
-#include "../ui/tree.h"
+#include "../ui/list.h"
 #include "../ui/text.h"
 #include "../ui/webview.h"
 #include "../ui/widget.h"
@@ -107,7 +107,7 @@ UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char
 UIEXPORT void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip);
 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_groups(UiToolbarItemArgs *args, int *states, int numstates);
+UIEXPORT void ui_toolbar_item_args_set_states(UiToolbarItemArgs *args, int *states, int numstates);
 UIEXPORT void ui_toolbar_item_args_free(UiToolbarItemArgs *args);
 
 UIEXPORT UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void);
@@ -117,7 +117,7 @@ UIEXPORT void ui_toolbar_toggleitem_args_set_tooltip(UiToolbarToggleItemArgs *ar
 UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname);
 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_groups(UiToolbarToggleItemArgs *args, int *states, int numstates);
+UIEXPORT void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *args, int *states, int numstates);
 UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
 
 UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
@@ -137,7 +137,7 @@ UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_left(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_top(UiContainerArgs *args, int value);
-UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_bottom(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_colspan(UiContainerArgs *args, int colspan);
 UIEXPORT void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan);
 UIEXPORT void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value);
@@ -346,7 +346,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_groups(UiButtonArgs *args, int *states, int numstates);
+UIEXPORT void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_button_args_free(UiButtonArgs *args);
 
 UIEXPORT UiToggleArgs* ui_toggle_args_new(void);
@@ -373,8 +373,8 @@ UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callba
 UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
 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_enablegroup(UiToggleArgs *args, int group);
-UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates);
+UIEXPORT void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state);
+UIEXPORT void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int numstates);
 UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
 
 UIEXPORT UiLinkButtonArgs* ui_linkbutton_args_new(void);
@@ -401,7 +401,7 @@ UIEXPORT void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback
 UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata);
 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_groups(UiLinkButtonArgs *args, int *states, int numstates);
+UIEXPORT void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_linkbutton_args_free(UiLinkButtonArgs *args);
 
 UIEXPORT UiListArgs* ui_list_args_new(void);
@@ -443,7 +443,7 @@ 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);
 UIEXPORT void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder);
-UIEXPORT void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates);
+UIEXPORT void ui_list_args_set_states(UiListArgs *args, int *states, int numstates);
 UIEXPORT void ui_list_args_free(UiListArgs *args);
 
 UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void);
@@ -495,7 +495,7 @@ UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback ca
 UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
 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_groups(UiTextAreaArgs *args, int *states, int numstates);
+UIEXPORT void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates);
 UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args);
 
 UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void);
@@ -520,7 +520,7 @@ UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callbac
 UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
 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_groups(UiTextFieldArgs *args, int *states, int numstates);
+UIEXPORT void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates);
 UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args);
 
 UIEXPORT UiSpinBoxArgs* ui_spinbox_args_new(void);
@@ -549,7 +549,7 @@ UIEXPORT void ui_spinbox_args_set_varname(UiSpinBoxArgs *args, const char *varna
 UIEXPORT void ui_spinbox_args_set_intvalue(UiSpinBoxArgs *args, UiInteger *value);
 UIEXPORT void ui_spinbox_args_set_doublevalue(UiSpinBoxArgs *args, UiDouble *value);
 UIEXPORT void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value);
-UIEXPORT void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates);
+UIEXPORT void ui_spinbox_args_set_states(UiSpinBoxArgs *args, int *states, int numstates);
 UIEXPORT void ui_spinbox_args_free(UiSpinBoxArgs *args);
 
 UIEXPORT UiWebviewArgs* ui_webview_args_new(void);
@@ -570,7 +570,7 @@ UIEXPORT void ui_webview_args_set_name(UiWebviewArgs *args, const char *name);
 UIEXPORT void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname);
 UIEXPORT void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname);
 UIEXPORT void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value);
-UIEXPORT void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates);
+UIEXPORT void ui_webview_args_set_states(UiWebviewArgs *args, int *states, int numstates);
 UIEXPORT void ui_webview_args_free(UiWebviewArgs *args);
 
 #ifdef __cplusplus
index 73911a5666f0ca2ce81b4028bbaec4db663bea9f..bd1d8558d46d13f0f85febd3b6dece6fdd8f730a 100644 (file)
@@ -64,8 +64,8 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16);
     
     ctx->documents = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, CX_STORE_POINTERS);
-    ctx->group_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiGroupWidget));
-    ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
+    ctx->state_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiStateWidget));
+    ctx->states = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
     
     ctx->attach_document = uic_context_attach_document;
     ctx->detach_document2 = uic_context_detach_document;
@@ -92,11 +92,17 @@ void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *d
 }
 
 void uic_context_prepare_close(UiContext *ctx) {
-    cxListClear(ctx->groups);
-    cxListClear(ctx->group_widgets);
+    cxListClear(ctx->states);
+    cxListClear(ctx->state_widgets);
 }
 
 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;
     
@@ -114,7 +120,7 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
             UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
             if(docvar) {
                 // bind var to document var
-                uic_copy_binding(var, docvar, TRUE);
+                uic_copy_var_binding(var, docvar, TRUE);
                 cxIteratorFlagRemoval(i);
             }
         }
@@ -124,16 +130,19 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
 }
 
 static void uic_context_unbind_vars(UiContext *ctx) {
+    ui_onchange_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);
         UiVar *var = entry->value;
         // var->from && var->from_ctx && var->from_ctx != ctx
         uic_save_var(var);
         if(var->from) {
-            uic_copy_binding(var, var->from, FALSE);
+            uic_copy_var_binding(var, var->from, FALSE);
             cxMapPut(var->from->from_ctx->vars, *entry->key, var->from);
             var->from = NULL;
         }
+        uic_unbind_var(var);
     }
     
     if(ctx->documents) {
@@ -143,6 +152,8 @@ static void uic_context_unbind_vars(UiContext *ctx) {
             uic_context_unbind_vars(subctx);
         }
     }
+    
+    ui_onchange_events_enable(TRUE);
 }
 
 void uic_context_detach_document(UiContext *ctx, void *document) {
@@ -197,6 +208,14 @@ UiVar* uic_get_var(UiContext *ctx, const char *name) {
     return ctx_getvar(ctx, key);
 }
 
+UiVar* uic_get_var_t(UiContext *ctx,const char *name, UiVarType type) {
+    UiVar *var = uic_get_var(ctx, name);
+    if(var && var->type == type) {
+        return var;
+    }
+    return NULL;
+}
+
 UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
     UiVar *var = uic_get_var(ctx, name);
     if(var) {
@@ -213,8 +232,9 @@ UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
     var->original_value = NULL;
     var->from = NULL;
     var->from_ctx = ctx;
-
-    cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var);
+    var->bound = FALSE;
+    
+    cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var); // TODO: use another destructor that cleans the value (UiString free, UiText destroy, ...)
 
     cxMapPut(ctx->vars, name, var);
     
@@ -266,6 +286,40 @@ void* uic_create_value(UiContext *ctx, UiVarType type) {
     return val;
 }
 
+// destroys a value, that was created by uic_create_value
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value) {
+    switch(type) {
+        default: {
+            ui_free(ctx, value);
+            break;
+        }
+        case UI_VAR_SPECIAL: break;
+        case UI_VAR_STRING: {
+            UiString *s = value;
+            if(s->value.free) {
+                s->value.free(s->value.ptr);
+            }
+            ui_free(ctx, value);
+        }
+        case UI_VAR_TEXT: {
+            UiText *t = value;
+            if(t->value.free) {
+                t->value.free(t->value.ptr);
+                t->value.free = NULL;
+                t->value.ptr = NULL;
+            }
+            if(t->destroy) {
+                t->destroy(t);
+            }
+            ui_free(ctx, value);
+        }
+        case UI_VAR_LIST: {
+            ui_list_free(ctx, value);
+            break;
+        }
+    }
+}
+
 
 UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) {
     if (value) {
@@ -278,7 +332,7 @@ UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, cons
 }
 
 
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
     // check type
     if(from->type != to->type) {
         fprintf(stderr, "UI Error: var has incompatible type.\n");
@@ -301,32 +355,36 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
         }
     }
     
-    ui_setop_enable(TRUE);
+    uic_copy_value_binding(from->type, fromvalue, tovalue);
+}
+
+void uic_copy_value_binding(UiVarType type, void *from, void *to) {
+     ui_setop_enable(TRUE);
     
     // copy binding
-    // we don't copy the observer, because the from var has never one
-    switch(from->type) {
+    // we don't copy the observer, because the from value never has oberservers
+    switch(type) {
         default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break;
         case UI_VAR_SPECIAL: break;
         case UI_VAR_INTEGER: {
-            UiInteger *f = fromvalue;
-            UiInteger *t = tovalue;
+            UiInteger *f = from;
+            UiInteger *t = to;
             if(!f->obj) break;
             uic_int_copy(f, t);
             t->set(t, t->value);
             break;
         }
         case UI_VAR_DOUBLE: {
-            UiDouble *f = fromvalue;
-            UiDouble *t = tovalue;
+            UiDouble *f = from;
+            UiDouble *t = to;
             if(!f->obj) break;
             uic_double_copy(f, t);
             t->set(t, t->value);
             break;
         }
         case UI_VAR_STRING: {
-            UiString *f = fromvalue;
-            UiString *t = tovalue;
+            UiString *f = from;
+            UiString *t = to;
             if(!f->obj) break;
             uic_string_copy(f, t);
             char *tvalue = t->value.ptr ? t->value.ptr : "";
@@ -335,23 +393,23 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
             break;
         }
         case UI_VAR_TEXT: {
-            UiText *f = fromvalue;
-            UiText *t = tovalue;
+            UiText *f = from;
+            UiText *t = to;
             if(!f->obj) break;
             uic_text_copy(f, t);
             t->restore(t);
             break;
         }
         case UI_VAR_LIST: {         
-            UiList *f = fromvalue;
-            UiList *t = tovalue;
+            UiList *f = from;
+            UiList *t = to;
             uic_list_copy(f, t);
             ui_list_update(t);
             break;
         }
         case UI_VAR_RANGE: {
-            UiRange *f = fromvalue;
-            UiRange *t = tovalue;
+            UiRange *f = from;
+            UiRange *t = to;
             if(!f->obj) break;
             uic_range_copy(f, t);
             t->setextent(t, t->extent);
@@ -360,8 +418,8 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
             break;
         }
         case UI_VAR_GENERIC: {
-            UiGeneric *f = fromvalue;
-            UiGeneric *t = tovalue;
+            UiGeneric *f = from;
+            UiGeneric *t = to;
             if(!f->obj) break;
             uic_generic_copy(f, t);
             t->set(t, t->value, t->type);
@@ -398,59 +456,56 @@ void uic_unbind_var(UiVar *var) {
     }
 }
 
+const char *uic_type2str(UiVarType type) {
+    switch(type) {
+        default: return "";
+        case UI_VAR_INTEGER: return "int";
+        case UI_VAR_DOUBLE: return "double";
+        case UI_VAR_STRING: return "string";
+        case UI_VAR_TEXT: return "text";
+        case UI_VAR_LIST: return "list";
+        case UI_VAR_RANGE: return "range";
+        case UI_VAR_GENERIC: return "generic";
+    }
+}
+
 void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) {
-    // TODO: do we need/want this? Why adding vars to a context after
-    // widgets reference these? Workarounds:
-    // 1. add vars to ctx before creating ui
-    // 2. create ui, create new document with vars, attach doc
-    // also it would be possible to create a function, that scans unbound vars
-    // and connects them to available vars
-    /*
-    UiContext *rootctx = uic_root_context(ctx); 
-    UiVar *b = NULL;
-    if(rootctx->bound) {
-        // some widgets are already bound to some vars
-        b = ucx_map_cstr_get(rootctx->bound, name);
-        if(b) {
-            // a widget is bound to a var with this name
-            // if ctx is the root context we can remove the var from bound
-            // because set_doc or detach can't fuck things up
-            if(ctx == rootctx) {
-                ucx_map_cstr_remove(ctx->bound, name);
-                // TODO: free stuff
-            }
+    UiVar *var = cxMapGet(ctx->vars, name);
+    if(!var) {
+        // create new var and add it to the context var map
+        var = ui_malloc(ctx, sizeof(UiVar));
+        cxMapPut(ctx->vars, name, var);
+    } else {
+        // override var with new value
+        if(var->type != type) {
+            fprintf(stderr, "Error: var %s type mismatch: %s - %s\n", name, uic_type2str(var->type), uic_type2str(type));
+            return;
+        }
+        if(var->bound) {
+            fprintf(stderr, "Error: var %s already bound\n", name);
+            return;
         }
+        UiInteger *prev_value = var->value;
+        uic_copy_value_binding(type, prev_value, value);
+        uic_destroy_value(var->from_ctx, var->type, var->value);
     }
-    */
     
-    // create new var and add it to doc's vars
-    UiVar *var = ui_malloc(ctx, sizeof(UiVar));
     var->type = type;
     var->value = value;
     var->from = NULL;
     var->from_ctx = ctx;
-    size_t oldcount = cxMapSize(ctx->vars);
-    cxMapPut(ctx->vars, name, var);
-    if(cxMapSize(ctx->vars) != oldcount + 1) {
-        fprintf(stderr, "UiError: var '%s' already exists\n", name);
-    }
-    
-    // TODO: remove?
-    // a widget is already bound to a var with this name
-    // copy the binding (like uic_context_set_document)
-    /*
-    if(b) {
-        uic_copy_binding(b, var, TRUE);
-    }
-    */
+    var->bound = TRUE;
 }
 
-void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
-    // TODO
-}
+// public API
 
+void* ui_context_get_document(UiContext *ctx) {
+    return ctx->document;
+}
 
-// public API
+void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable) {
+    ctx->single_document_mode = enable;
+}
 
 void ui_attach_document(UiContext *ctx, void *document) {
     uic_context_attach_document(ctx, document);
@@ -478,48 +533,48 @@ UiContext* ui_context_parent(UiContext *ctx) {
 }
 
 
-void ui_set_group(UiContext *ctx, int group) {
-    if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) {
-        cxListAdd(ctx->groups, &group);
+void ui_set_state(UiContext *ctx, int state) {
+    if(!cxListIndexValid(ctx->states, cxListFind(ctx->states, &state))) {
+        cxListAdd(ctx->states, &state);
     }
     
     // enable/disable group widgets
-    uic_check_group_widgets(ctx);
+    uic_check_state_widgets(ctx);
 }
 
-void ui_unset_group(UiContext *ctx, int group) {
-    int i = cxListFind(ctx->groups, &group);
+void ui_unset_state(UiContext *ctx, int state) {
+    int i = cxListFind(ctx->states, &state);
     if(i != -1) {
-        cxListRemove(ctx->groups, i);
+        cxListRemove(ctx->states, i);
     }
     
     // enable/disable group widgets
-    uic_check_group_widgets(ctx);
+    uic_check_state_widgets(ctx);
 }
 
-int* ui_active_groups(UiContext *ctx, int *ngroups) {
-    *ngroups = cxListSize(ctx->groups);
-    return cxListAt(ctx->groups, 0);
+int* ui_active_states(UiContext *ctx, int *nstates) {
+    *nstates = cxListSize(ctx->states);
+    return cxListAt(ctx->states, 0);
 }
 
-void uic_check_group_widgets(UiContext *ctx) {
+void uic_check_state_widgets(UiContext *ctx) {
     int ngroups = 0;
-    int *groups = ui_active_groups(ctx, &ngroups);
+    int *groups = ui_active_states(ctx, &ngroups);
     
-    CxIterator i = cxListIterator(ctx->group_widgets);
-    cx_foreach(UiGroupWidget *, gw, i) {
-        char *check = calloc(1, gw->numgroups);
+    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 k=0;k<gw->numgroups;k++) {
-                if(groups[i] == gw->groups[k]) {
+            for(int k=0;k<gw->numstates;k++) {
+                if(groups[i] == gw->states[k]) {
                     check[k] = 1;
                 }
             }
         }
         
         int enable = 1;
-        for(int i=0;i<gw->numgroups;i++) {
+        for(int i=0;i<gw->numstates;i++) {
             if(check[i] == 0) {
                 enable = 0;
                 break;
@@ -530,70 +585,70 @@ void uic_check_group_widgets(UiContext *ctx) {
     }
 }
 
-void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
+void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
     if(enable == NULL) {
         enable = (ui_enablefunc)ui_set_enabled;
     }
-    // get groups
-    CxList *groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
+    // get states
+    CxList *states = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
     va_list ap;
     va_start(ap, enable);
-    int group;
-    while((group = va_arg(ap, int)) != -1) {
-        cxListAdd(groups, &group);
+    int state;
+    while((state = va_arg(ap, int)) != -1) {
+        cxListAdd(states, &state);
     }
     va_end(ap);
     
-    uic_add_group_widget(ctx, widget, enable, groups);
+    uic_add_state_widget(ctx, widget, enable, states);
     
-    cxListFree(groups);
+    cxListFree(states);
 }
 
-void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups) {
+void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates) {
     if(enable == NULL) {
         enable = (ui_enablefunc)ui_set_enabled;
     }
-    CxList *ls = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), ngroups);
-    for(int i=0;i<ngroups;i++) {
-        cxListAdd(ls, groups+i);
+    CxList *ls = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), nstates);
+    for(int i=0;i<nstates;i++) {
+        cxListAdd(ls, states+i);
     }
-    uic_add_group_widget(ctx, widget, enable, ls);
+    uic_add_state_widget(ctx, widget, enable, ls);
     cxListFree(ls);
 }
 
 void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates) {
-    ui_widget_set_groups2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates);
+    ui_widget_set_states2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates);
 }
 
-size_t uic_group_array_size(const int *groups) {
+size_t uic_state_array_size(const int *states) {
     int i;
-    for(i=0;groups[i] >= 0;i++) { }
+    for(i=0;states[i] >= 0;i++) { }
     return i;
 }
 
-void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups) {
-    uic_add_group_widget_i(ctx, widget, enable, cxListAt(groups, 0), cxListSize(groups));
+void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *states) {
+    uic_add_state_widget_i(ctx, widget, enable, cxListAt(states, 0), cxListSize(states));
 }
 
-void uic_add_group_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *groups, size_t numgroups) {
+void uic_add_state_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *states, size_t numstates) {
     const CxAllocator *a = ctx->allocator;
-    UiGroupWidget gw;
+    UiStateWidget gw;
     
     gw.widget = widget;
     gw.enable = enable;
-    gw.numgroups = numgroups;
-    gw.groups = cxCalloc(a, numgroups, sizeof(int));
+    gw.numstates = numstates;
+    gw.states = cxCalloc(a, numstates, sizeof(int));
     
-    // copy groups
-    if(groups) {
-        memcpy(gw.groups, groups, gw.numgroups * sizeof(int));
+    // copy states
+    if(states) {
+        memcpy(gw.states, states, gw.numstates * sizeof(int));
     }
     
-    cxListAdd(ctx->group_widgets, &gw);
+    cxListAdd(ctx->state_widgets, &gw);
 }
 
-void uic_remove_group_widget(UiContext *ctx, void *widget) {
-    (void)cxListFindRemove(ctx->group_widgets, widget);
+void uic_remove_state_widget(UiContext *ctx, void *widget) {
+    (void)cxListFindRemove(ctx->state_widgets, widget);
 }
 
 UIEXPORT void *ui_allocator(UiContext *ctx) {
@@ -638,3 +693,33 @@ void  ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) {
 void  ui_set_destructor(void *mem, ui_destructor_func destr) {
     cxMempoolSetDestructor(mem, (cx_destructor_func)destr);
 }
+
+UiInteger* ui_get_int_var(UiContext *ctx, const char *name) {
+    UiVar *var = uic_get_var_t(ctx, name, UI_VAR_INTEGER);
+    return var ? var->value : NULL;
+}
+
+UiDouble* ui_get_double_var(UiContext *ctx, const char *name) {
+    UiVar *var = uic_get_var_t(ctx, name, UI_VAR_DOUBLE);
+    return var ? var->value : NULL;
+}
+
+UiString* ui_get_string_var(UiContext *ctx, const char *name) {
+    UiVar *var = uic_get_var_t(ctx, name, UI_VAR_STRING);
+    return var ? var->value : NULL;
+}
+
+UiText* ui_get_text_var(UiContext *ctx, const char *name) {
+    UiVar *var = uic_get_var_t(ctx, name, UI_VAR_TEXT);
+    return var ? var->value : NULL;
+}
+
+UiRange* ui_get_range_var(UiContext *ctx, const char *name) {
+    UiVar *var = uic_get_var_t(ctx, name, UI_VAR_RANGE);
+    return var ? var->value : NULL;
+}
+
+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;
+}
index f5170902d2a5a2c657936a9af0cc047fb929f76b..5efcc2ee50d8a2d0a11494dc012a46c623463d5d 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
 typedef struct UiVar            UiVar;
 typedef struct UiListPtr        UiListPtr;
 typedef struct UiListVar        UiListVar;
-typedef struct UiGroupWidget    UiGroupWidget;
+typedef struct UiStateWidget    UiStateWidget;
 typedef struct UiDestroyHandler UiDestroyHandler;
 
 typedef enum UiVarType {
@@ -69,8 +69,8 @@ struct UiContext {
     
     CxMap         *vars;
     
-    CxList        *groups; // int list
-    CxList        *group_widgets; // UiGroupWidget list
+    CxList        *states; // int list
+    CxList        *state_widgets; // UiGroupWidget list
     
     void (*attach_document)(UiContext *ctx, void *document);
     void (*detach_document2)(UiContext *ctx, void *document); 
@@ -84,8 +84,10 @@ struct UiContext {
     GtkAccelGroup *accel_group;
 #endif 
 #endif
-
-
+    
+    // allow only one document to be attached
+    // attaching a document will automatically detach the current document
+    UiBool single_document_mode;
     
     ui_callback   close_callback;
     void          *close_data;
@@ -97,13 +99,14 @@ struct UiVar {
     UiVarType type;
     UiVar     *from;
     UiContext *from_ctx;
+    UiBool    bound;
 };
 
-struct UiGroupWidget {
+struct UiStateWidget {
     void          *widget;
     ui_enablefunc enable;
-    int           *groups;
-    int           numgroups;
+    int           *states;
+    int           numstates;
 };
 
 struct UiDestroyHandler {
@@ -127,25 +130,27 @@ void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
 void uic_context_detach_all(UiContext *ctx);
 
 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);
 UiVar* uic_create_value_var(UiContext *ctx, void *value);
 void* uic_create_value(UiContext *ctx, UiVarType type);
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value);
 
 UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type);
 
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_value_binding(UiVarType type, void *from, void *to);
 void uic_save_var(UiVar *var);
 void uic_unbind_var(UiVar *var);
+const char *uic_type2str(UiVarType type);
 
 void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
 
-void uic_remove_bound_var(UiContext *ctx, UiVar *var);
-
-size_t uic_group_array_size(const int *groups);
-void uic_check_group_widgets(UiContext *ctx);
-void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups);
-void uic_add_group_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *groups, size_t numgroups);
-void uic_remove_group_widget(UiContext *ctx, void *widget);
+size_t uic_state_array_size(const int *states);
+void uic_check_state_widgets(UiContext *ctx);
+void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *states);
+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);
 
 #ifdef __cplusplus
 }
index b0cfc46bbe59052c37abde53c0616815aea4a55d..64c49c19ffcf702349b528b74fe7209378723471 100644 (file)
@@ -89,20 +89,20 @@ static char* nl_strdup(const char* s) {
     return s ? strdup(s) : NULL;
 }
 
-int* uic_copy_groups(const int* groups, size_t *ngroups) {
-    *ngroups = 0;
-    if (!groups) {
+int* uic_copy_states(const int* states, size_t *nstates) {
+    *nstates = 0;
+    if (!states) {
         return NULL;
     }
 
     size_t n;
-    for (n = 0; groups[n] > -1; n++) { }
+    for (n = 0; states[n] > -1; n++) { }
 
-    if (ngroups > 0) {
+    if (nstates > 0) {
         int* newarray = calloc(n+1, sizeof(int));
-        memcpy(newarray, groups, n * sizeof(int));
+        memcpy(newarray, states, n * sizeof(int));
         newarray[n] = -1;
-        *ngroups = n;
+        *nstates = n;
         return newarray;
     }
     return NULL;
@@ -152,7 +152,7 @@ void ui_menuitem_create(UiMenuItemArgs *args) {
     item->icon = nl_strdup(args->icon);
     item->userdata = args->onclickdata;
     item->callback = args->onclick;
-    item->groups = uic_copy_groups(args->groups, &item->ngroups);
+    item->states = uic_copy_states(args->states, &item->nstates);
 
     add_item((UiMenuItemI*)item);
 }
@@ -179,7 +179,7 @@ void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args) {
     item->varname = nl_strdup(args->varname);
     item->userdata = args->onchangedata;
     item->callback = args->onchange;
-    item->groups = uic_copy_groups(args->groups, &item->ngroups);
+    item->states = uic_copy_states(args->nstates, &item->nstates);
     
     add_item((UiMenuItemI*)item);
 }
@@ -196,7 +196,7 @@ void ui_menu_radioitem_create(UiMenuToggleItemArgs *args) {
     item->varname = nl_strdup(args->varname);
     item->userdata = args->onchangedata;
     item->callback = args->onchange;
-    item->groups = uic_copy_groups(args->groups, &item->ngroups);
+    item->states = uic_copy_states(args->nstates, &item->nstates);
 
     add_item((UiMenuItemI*)item);
 }
@@ -296,14 +296,14 @@ static void free_menuitem(UiMenuItemI *item) {
         }
         case UI_MENU_ITEM: {
             UiMenuItem *i = (UiMenuItem*)item;
-            free(i->groups);
+            free(i->states);
             free(i->label);
             free(i->icon);
             break;
         }
         case UI_MENU_CHECK_ITEM: {
             UiMenuCheckItem *i = (UiMenuCheckItem*)item;
-            free(i->groups);
+            free(i->states);
             free(i->label);
             free(i->icon);
             free(i->varname);
@@ -311,7 +311,7 @@ static void free_menuitem(UiMenuItemI *item) {
         }
         case UI_MENU_RADIO_ITEM: {
             UiMenuRadioItem *i = (UiMenuRadioItem*)item;
-            free(i->groups);
+            free(i->states);
             free(i->label);
             free(i->icon);
             free(i->varname);
index f44f6b4f9504333acdae7bc1fa6debe34e88cca6..9aea5789962c531fddfc7e618f7307197a1c275f 100644 (file)
@@ -79,8 +79,8 @@ struct UiMenuItem {
     char           *label;
     char           *icon;
     void           *userdata;
-    int            *groups;
-    size_t         ngroups;
+    int            *states;
+    size_t         nstates;
 };
 
 struct UiMenuCheckItem {
@@ -90,8 +90,8 @@ struct UiMenuCheckItem {
     char           *varname;
     ui_callback    callback;
     void           *userdata;
-    int            *groups;
-    size_t         ngroups;
+    int            *states;
+    size_t         nstates;
 };
 
 struct UiMenuRadioItem {
@@ -101,8 +101,8 @@ struct UiMenuRadioItem {
     char           *varname;
     ui_callback    callback;
     void           *userdata;
-    int            *groups;
-    size_t         ngroups;
+    int            *states;
+    size_t         nstates;
 };
 
 struct UiMenuItemList {
@@ -129,7 +129,7 @@ UiMenu* uic_get_menu_list(void);
 
 void uic_add_menu_to_stack(UiMenu* menu);
 
-int* uic_copy_groups(const int* groups, size_t *ngroups);
+int* uic_copy_states(const int* states, size_t *nstates);
 
 void uic_set_tmp_eventdata(void *eventdata, int type);
 void* uic_get_tmp_eventdata(void);
diff --git a/ui/common/message.c b/ui/common/message.c
new file mode 100644 (file)
index 0000000..30ef304
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 _WIN32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "message.h"
+
+int uic_message_send_(UiMessageHandler *handler, cxstring msg) {
+    return handler->send(handler, msg);
+}
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback) {
+    UiSimpleMessageHandler *handler = malloc(sizeof(UiSimpleMessageHandler));
+    handler->handler.start = uic_simple_msg_handler_start;
+    handler->handler.stop = uic_simple_msg_handler_stop;
+    handler->handler.send = uic_simple_msg_handler_send;
+    handler->handler.callback = callback;
+    handler->in = in;
+    handler->out = out;
+    handler->outbuf = cxBufferCreate(NULL, 4096, NULL, CX_BUFFER_FREE_CONTENTS | CX_BUFFER_AUTO_EXTEND);
+    handler->stop = 0;
+    pthread_mutex_init(&handler->queue_lock, NULL);
+    pthread_mutex_init(&handler->avlbl_lock, NULL);
+    pthread_cond_init(&handler->available, NULL);  
+    return (UiMessageHandler*)handler;
+}
+
+int uic_simple_msg_handler_start(UiMessageHandler *handler) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    if(pthread_create(&sh->in_thread, NULL, uic_simple_msg_handler_in_thread, sh)) {
+        return 1;
+    }
+    if(pthread_create(&sh->out_thread, NULL, uic_simple_msg_handler_out_thread, sh)) {
+        return 1;
+    }
+    return 0;
+}
+
+int uic_simple_msg_handler_stop(UiMessageHandler *handler) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    pthread_mutex_lock(&sh->queue_lock);
+    sh->stop = 0;
+    pthread_cond_signal(&sh->available);
+    pthread_mutex_unlock(&sh->queue_lock);
+    close(sh->in);
+    sh->in = -1;
+    
+    pthread_join(sh->in_thread, NULL);
+    pthread_join(sh->out_thread, NULL);
+    
+    return 0;
+}
+
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    pthread_mutex_lock(&sh->queue_lock);
+    char header[32];
+    snprintf(header, 32, "%zu\n", msg.length);
+    cxBufferPutString(sh->outbuf, header);
+    cxBufferWrite(msg.ptr, 1, msg.length, sh->outbuf);
+    pthread_cond_signal(&sh->available);
+    pthread_mutex_unlock(&sh->queue_lock);
+    return 0;
+}
+
+#define HEADERBUF_SIZE 64
+
+void* uic_simple_msg_handler_in_thread(void *data) {
+    UiSimpleMessageHandler *handler = data;
+    
+    char *msg = NULL;
+    size_t msg_size = 0;
+    size_t msg_pos = 0; // currently received message length
+    
+    char headerbuf[HEADERBUF_SIZE];
+    size_t headerpos = 0;
+    
+    char buf[2048];
+    ssize_t r;
+    while((r = read(handler->in, buf, 2024)) > 0) {
+        char *buffer = buf;
+        size_t available = r;
+        
+        while(available > 0) {
+            if(msg) {
+                // read message
+                size_t need = msg_size - msg_pos;
+                size_t cplen = r > need ? need : available;
+                memcpy(msg+msg_pos, buffer, cplen);
+                buffer += cplen;
+                available -= cplen;
+                msg_pos += cplen;
+                if(msg_pos == msg_size) {
+                    // message complete
+                    //fprintf(stderr, "send: %.*s\n", (int)msg_size, msg);
+                    if(handler->handler.callback) {
+                        handler->handler.callback(cx_strn(msg, msg_size));
+                    }
+                    free(msg);
+                    msg = NULL;
+                    msg_size = 0;
+                    msg_pos = 0;
+                }
+            } else {
+                size_t header_max = HEADERBUF_SIZE - headerpos - 1;
+                if(header_max > available) {
+                    header_max = available;
+                }
+                // search for line break
+                int i;
+                int header_complete = 0;
+                for(i=0;i<header_max;i++) {
+                    if(buffer[i] == '\n') {
+                        header_complete = 1;
+                        break;
+                    }
+                }
+                i++;
+                memcpy(headerbuf+headerpos, buffer, i);
+                headerpos += i;
+                buffer += i;
+                available -= i;
+                
+                if(header_complete) {
+                    headerbuf[headerpos-1] = 0; // terminate buffer
+                    char *end;
+                    long length = strtol(headerbuf, &end, 10);
+                    if(*end == '\0') {
+                        //fprintf(stderr, "header: %d\n", (int)length);
+                        msg = malloc(length);
+                        msg_size = length;
+                        headerpos = 0;
+                    } else {
+                        fprintf(stderr, "Error: invalid message {%s}\n", headerbuf);
+                    }
+                } else if(headerpos+1 >= HEADERBUF_SIZE) {
+                    fprintf(stderr, "Error: message header too big\n");
+                    exit(-1);
+                }
+            }
+        }
+        
+        
+    }
+    perror("error");
+    fprintf(stderr, "stop simple_msg_handler_in_thread\n");
+    
+    return NULL;
+}
+
+void* uic_simple_msg_handler_out_thread(void *data) {
+    UiSimpleMessageHandler *handler = data;
+    CxBuffer *buffer = handler->outbuf;
+    
+    pthread_mutex_lock(&handler->queue_lock);
+    
+    for(;;) {
+        if(buffer->pos == 0) {
+            pthread_cond_wait(&handler->available, &handler->queue_lock);
+            continue;
+        } else {
+            size_t n = buffer->pos;
+            size_t pos = 0;
+            while(n > 0) {
+                ssize_t w = write(handler->out, buffer->space + pos, n);
+                if(w <= 0) {
+                    fprintf(stderr, "Error: output error\n");
+                    break;
+                }
+                n -= w;
+                pos += w;
+            }
+            if(n > 0) {
+                break; // error
+            }
+            buffer->pos = 0;
+        }
+    }
+    
+    pthread_mutex_unlock(&handler->queue_lock);
+    
+    return NULL;
+}
+
+#endif
diff --git a/ui/common/message.h b/ui/common/message.h
new file mode 100644 (file)
index 0000000..83cb135
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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_MESSAGE_H
+#define UIC_MESSAGE_H
+
+
+#include <cx/string.h>
+#include <cx/json.h>
+#include <cx/buffer.h>
+
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct UiMessageHandler UiMessageHandler;
+
+typedef void(*msg_received_callback)(cxstring msg);
+
+struct UiMessageHandler {
+    int (*start)(UiMessageHandler *handler);
+    int (*stop)(UiMessageHandler *handler);
+    int (*send)(UiMessageHandler *handler, cxstring msg);
+    
+    msg_received_callback callback;
+};
+
+typedef struct UiSimpleMessageHandler {
+    UiMessageHandler handler;
+    int in;
+    int out;
+#ifndef _WIN32
+    pthread_t in_thread;
+    pthread_t out_thread;
+    pthread_mutex_t queue_lock;
+    pthread_mutex_t avlbl_lock;
+    pthread_cond_t  available;
+#endif
+    CxBuffer *outbuf;
+    int stop;
+} UiSimpleMessageHandler;
+
+int uic_message_send_(UiMessageHandler *handler, cxstring msg);
+#define uic_message_send(handler, msg) uic_message_send_(handler, cx_strcast(msg))
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback);
+int uic_simple_msg_handler_start(UiMessageHandler *handler);
+int uic_simple_msg_handler_stop(UiMessageHandler *handler);
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg);
+
+void* uic_simple_msg_handler_in_thread(void *data);
+void* uic_simple_msg_handler_out_thread(void *data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_MESSAGE_H */
+
index b041bc9b22b4bf25c07902cc2b753d07d51a97fe..9b0a8b7b022a1481bf05798ab9c72c2cc0b96c6b 100644 (file)
@@ -32,6 +32,7 @@
 #include "context.h"
 
 #include <cx/linked_list.h>
+#include <cx/hash_map.h>
 
 #include "../ui/container.h"
 
@@ -108,7 +109,7 @@ void uic_object_destroy(UiObject *obj) {
 UiObject* uic_object_new_toplevel(void) {
     fflush(stdout);
     CxMempool *mp = cxMempoolCreateSimple(256);
-    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate));
     fflush(stdout);
     obj->ctx = uic_context(obj, mp);
     obj->ctx->parent = ui_global_context();
@@ -119,7 +120,7 @@ UiObject* uic_object_new_toplevel(void) {
 }
 
 UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
-    UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
+    UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObjectPrivate));
     newobj->ctx = ctx;
     newobj->widget = widget;
     uic_object_created(newobj);
@@ -170,3 +171,22 @@ void uic_object_remove_second_last_container(UiObject *toplevel) {
         fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
     }
 }
+
+// public API
+
+void ui_object_set(UiObject *obj, const char *key, void *data) {
+    UiObjectPrivate *p = (UiObjectPrivate*)obj;
+    if(!p->ext) {
+        p->ext = cxHashMapCreate(obj->ctx->mp->allocator, CX_STORE_POINTERS, 4);
+    }
+    if(data) {
+        cxMapPut(p->ext, key, data);
+    } else {
+        cxMapRemove(p->ext, key);
+    }
+}
+
+void* ui_object_get(UiObject *obj, const char *key) {
+    UiObjectPrivate *p = (UiObjectPrivate*)obj;
+    return p->ext ? cxMapGet(p->ext, key) : NULL;
+}
index e6dd3c3e2ddf8c2aaf63316766455d534e2c400e..43278752ef904f4cef2741721d3b639f66ff6832 100644 (file)
 #define        UIC_OBJECT_H
 
 #include "../ui/toolkit.h"
+#include <cx/map.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+    
+typedef struct UiObjectPrivate {
+    UiObject obj;
+    CxMap *ext;
+} UiObjectPrivate;
 
 typedef void (*ui_object_callback)(UiObject *obj, void *userdata);
 
index 4d401b54643e134cc4fc7275f965b749da4b836b..3b49d856f5fa178262dcb72b04ce19092f1315b9 100644 (file)
@@ -34,6 +34,7 @@ COMMON_OBJ += document$(OBJ_EXT)
 COMMON_OBJ += object$(OBJ_EXT)
 COMMON_OBJ += container$(OBJ_EXT)
 COMMON_OBJ += types$(OBJ_EXT)
+COMMON_OBJ += app$(OBJ_EXT)
 COMMON_OBJ += properties$(OBJ_EXT)
 COMMON_OBJ += menu$(OBJ_EXT)
 COMMON_OBJ += toolbar$(OBJ_EXT)
@@ -42,6 +43,8 @@ COMMON_OBJ += threadpool$(OBJ_EXT)
 COMMON_OBJ += condvar$(OBJ_EXT)
 COMMON_OBJ += args$(OBJ_EXT)
 COMMON_OBJ += wrapper$(OBJ_EXT)
+COMMON_OBJ += utils$(OBJ_EXT)
+COMMON_OBJ += message$(OBJ_EXT)
 
 TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
 TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
index 28676fb08fe84c06d1e5c501351a7fbdc3d75496..33ffaea44965506666e70723f07f3aac7702d25d 100644 (file)
@@ -54,6 +54,8 @@ static CxMap *language;
 static char *locales_dir;
 static char *pixmaps_dir;
 
+static UiBool use_xdg_config_home = TRUE;
+
 #endif
 
 
@@ -73,6 +75,8 @@ char* ui_getappdir(void) {
 #define UI_ENV_HOME "USERPROFILE"
 #endif
 
+#define UI_XDG_CONFIG_HOME_VAR "XDG_CONFIG_HOME"
+
 char* ui_configfile(const char *name) {
     const char *appname = ui_appname();
     if(!appname) {
@@ -102,8 +106,23 @@ char* ui_configfile(const char *name) {
     // on Windows the app dir is $USERPROFILE/AppData/Local/$APPNAME/
     cxBufferPutString(&buf, "AppData\\Local\\");
 #else
-    // app dir is $HOME/.$APPNAME/
-    cxBufferPut(&buf, '.');
+    if(use_xdg_config_home) {
+        // app dir is $HOME/.config/$APPNAME/
+        char *xdghome = getenv(UI_XDG_CONFIG_HOME_VAR);
+        size_t xdghomelen = xdghome ? strlen(xdghome) : 0;
+        if(xdghome && xdghomelen > 0) {
+            cxBufferSeek(&buf, 0, SEEK_SET);
+            cxBufferPutString(&buf, xdghome);
+            if(xdghome[xdghomelen-1] != '/') {
+                cxBufferPut(&buf, '/');
+            }
+        } else {
+            cxBufferPutString(&buf, ".config/");
+        }
+    } else {
+        cxBufferPut(&buf, '.');
+    }
+    
 #endif
     cxBufferPutString(&buf, appname);
     cxBufferPut(&buf, UI_PATH_SEPARATOR);
@@ -139,9 +158,37 @@ void uic_load_app_properties() {
     if(!dir) {
         return;
     }
+    size_t len = strlen(dir);
+    if(len < 2) {
+        return;
+    }
     if(ui_mkdir(dir)) {
+        if(errno == ENOENT) {
+            char *parent = strdup(dir);
+            for(int i=len-2;i>=0;i--) {
+                if(parent[i] == '/') {
+                    parent[i] = 0;
+                    break;
+                }
+            }
+            // try creating the parent
+            int err = ui_mkdir(parent);
+            if(err) {
+                fprintf(stderr, "Error: Cannot create directory %s: %s\n", strerror(errno));
+                free(parent);
+                free(dir);
+                return;
+            }
+            free(parent);
+            
+            // try dir again
+            if(!ui_mkdir(dir)) {
+                errno = EEXIST; // success
+            }
+        }
+        
         if(errno != EEXIST) {
-            fprintf(stderr, "Ui Error: Cannot create directory %s\n", dir);
+            fprintf(stderr, "Error: Cannot create directory %s: %s\n", dir, strerror(errno));
             free(dir);
             return;
         }
index 7988eab577a9daa66999cc6d34e08891a7ab5b7d..3b4c096509861abc266c59e5698daf5aa16d342e 100644 (file)
@@ -40,24 +40,20 @@ static threadpool_job kill_job;
 
 UiThreadpool* threadpool_new(int min, int max) {
     UiThreadpool *pool = malloc(sizeof(UiThreadpool));
-    pool->queue = NULL;
-    pool->queue_len = 0;
+    pool->queue = ui_queue_create();
     pool->num_idle = 0;
     pool->min_threads = min;
     pool->max_threads = max;
 
-    pthread_mutex_init(&pool->queue_lock, NULL);
-    pthread_mutex_init(&pool->avlbl_lock, NULL);
-    pthread_cond_init(&pool->available, NULL);  
-
     return pool;
 }
 
 int threadpool_start(UiThreadpool *pool) {
+    pool->nthreads = pool->min_threads;
+    pool->threads = calloc(pool->max_threads, sizeof(pthread_t));
     /* create pool threads */
-    for(int i=0;i<pool->min_threads;i++) {
-        pthread_t t;
-        if (pthread_create(&t, NULL, threadpool_func, pool) != 0) {
+    for(int i=0;i<pool->nthreads;i++) {
+        if (pthread_create(&pool->threads[i], NULL, threadpool_func, pool) != 0) {
             fprintf(stderr, "uic: threadpool_start: pthread_create failed: %s", strerror(errno));
             return 1;
         }
@@ -65,6 +61,16 @@ int threadpool_start(UiThreadpool *pool) {
     return 0;
 }
 
+int threadpool_join(UiThreadpool *pool) {
+    int err = 0;
+    for(int i=0;i<pool->nthreads;i++) {
+        if(pthread_join(pool->threads[i], NULL)) {
+            err = 1;
+        }
+    }
+    return err;
+}
+
 void* threadpool_func(void *data) {
     UiThreadpool *pool = (UiThreadpool*)data;
     
@@ -82,71 +88,19 @@ void* threadpool_func(void *data) {
 }
 
 threadpool_job* threadpool_get_job(UiThreadpool *pool) {
-    pthread_mutex_lock(&pool->queue_lock);
-
-    threadpool_job *job = NULL;
-    pool->num_idle++;
-    while(job == NULL) {
-        if(pool->queue_len == 0) {
-            pthread_cond_wait(&pool->available, &pool->queue_lock);
-            continue;
-        } else {
-            pool_queue_t *q = pool->queue;
-            job = q->job;
-            pool->queue = q->next;
-            pool->queue_len--;
-            free(q);
-        }
-    }
-    pool->num_idle--;
-
-    pthread_mutex_unlock(&pool->queue_lock);
+    threadpool_job *job = ui_queue_get_wait(pool->queue); 
     return job;
 }
 
-void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) {
-    // TODO: handle errors
-    
+void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) { 
     threadpool_job *job = malloc(sizeof(threadpool_job));
     job->callback = func;
     job->data = data;
-
-    pthread_mutex_lock(&pool->queue_lock);
-    threadpool_enqueue_job(pool, job);
-
-    int create_thread = 0;
-    int destroy_thread = 0;
-    int diff = pool->queue_len - pool->num_idle;
-    
-    //if(pool->queue_len == 1) {
-    pthread_cond_signal(&pool->available);
-    //}
-    
-    pthread_mutex_unlock(&pool->queue_lock);
-}
-
-void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) {
-    pool_queue_t *q = malloc(sizeof(pool_queue_t));
-    q->job = job;
-    q->next = NULL;
-    
-    if(pool->queue == NULL) {
-        pool->queue = q;
-    } else {
-        pool_queue_t *last_elem = pool->queue;
-        while(last_elem->next != NULL) {
-            last_elem = last_elem->next;
-        }
-        last_elem->next = q;
-    }
-    pool->queue_len++;
+    ui_queue_put(pool->queue, job);
 }
 
 
 
-
-
-
 UiThreadpool* ui_threadpool_create(int nthreads) {
     UiThreadpool *pool = threadpool_new(nthreads, nthreads);
     threadpool_start(pool); // TODO: check return value
@@ -191,6 +145,71 @@ void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void
     threadpool_run(pool, ui_threadpool_job_func, job);
 }
 
+/* --------------------------------- Queue --------------------------------- */
+
+UiQueue* ui_queue_create(void) {
+    UiQueue *queue = calloc(1, sizeof(UiQueue));
+    pthread_mutex_init(&queue->lock, NULL);
+    pthread_mutex_init(&queue->avlbl_lock, NULL);
+    pthread_cond_init(&queue->available, NULL);
+    return queue;
+}
+
+void ui_queue_free(UiQueue *queue) {
+    // The queue must be empty, we could free UiQueueElm,
+    // but not the payload data
+    pthread_mutex_destroy(&queue->lock);
+    pthread_mutex_destroy(&queue->avlbl_lock);
+    pthread_cond_destroy(&queue->available);
+    free(queue);
+}
+
+void ui_queue_put(UiQueue *queue, void *data) {
+    // create queue element
+    UiQueueElm *elm = malloc(sizeof(UiQueueElm));
+    elm->data = data;
+    elm->next = NULL;
+    
+    pthread_mutex_lock(&queue->lock);
+    
+    // put queue element at the end of the linked list
+    if(queue->elements) {
+        UiQueueElm *end = queue->elements;
+        while(end->next) {
+            end = end->next;
+        }
+        end->next = elm;
+    } else {
+        queue->elements = elm;
+    }
+    queue->length++;
+    
+    // signal new available data
+    pthread_cond_signal(&queue->available);
+    
+    pthread_mutex_unlock(&queue->lock);
+}
+
+void* ui_queue_get_wait(UiQueue *queue) {
+    pthread_mutex_lock(&queue->lock);
+
+    void *data = NULL;
+    while(data == NULL) {
+        if(queue->length == 0) {
+            pthread_cond_wait(&queue->available, &queue->lock);
+            continue;
+        } else {
+            UiQueueElm *q = queue->elements;
+            data = q->data;
+            queue->elements = q->next;
+            queue->length--;
+            free(q);
+        }
+    }
+
+    pthread_mutex_unlock(&queue->lock);
+    return data;
+}
 
 #endif
 
index d167062e17c68bad4b979b18266cdd66815f2014..4a997f6802a0cab9f4af2a630c935749263f9720 100644 (file)
@@ -39,6 +39,8 @@
 extern "C" {
 #endif
     
+typedef struct UiQueueElm UiQueueElm;
+typedef struct UiQueue    UiQueue;
     
 typedef struct UiJob {
     UiObject      *obj;
@@ -48,20 +50,30 @@ typedef struct UiJob {
     void          *finish_data;
 } UiJob;
     
+struct UiQueueElm {
+    void       *data;
+    UiQueueElm *next;
+};
+
+struct UiQueue {
+    UiQueueElm      *elements;
+    size_t          length;
+    pthread_mutex_t lock;
+    pthread_mutex_t avlbl_lock;
+    pthread_cond_t  available;
+};
     
 typedef struct  _threadpool_job   threadpool_job;
 typedef void*(*job_callback_f)(void *data);
     
 typedef struct _pool_queue pool_queue_t;
 struct UiThreadpool {
-    pthread_mutex_t queue_lock;
-    pthread_mutex_t avlbl_lock;
-    pthread_cond_t  available;
-    pool_queue_t    *queue;
-    uint32_t        queue_len;
-    uint32_t        num_idle;
-    int             min_threads;
-    int             max_threads;
+    UiQueue   *queue;
+    uint32_t  num_idle;
+    int       min_threads;
+    int       max_threads;
+    pthread_t *threads;
+    int       nthreads;
 };
 
 struct _threadpool_job {
@@ -76,10 +88,15 @@ struct _pool_queue {
 
 UiThreadpool* threadpool_new(int min, int max);
 int threadpool_start(UiThreadpool *pool);
+int threadpool_join(UiThreadpool *pool);
 void* threadpool_func(void *data);
 threadpool_job* threadpool_get_job(UiThreadpool *pool);
 void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data);
-void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job);
+
+UiQueue* ui_queue_create(void);
+void ui_queue_free(UiQueue *queue);
+void ui_queue_put(UiQueue *queue, void *data);
+void* ui_queue_get_wait(UiQueue *queue);
 
 #ifdef __cplusplus
 }
index f237290dd0419275d0cd8bf78458b8c08fc95e17..eed1246e0d634c5bc7ca3dfbead09f29035940e2 100644 (file)
@@ -57,15 +57,15 @@ 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.groups = uic_copy_groups(args->groups, ngroups);\r
-    newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\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
 void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args) {\r
     UiToolbarItem* item = malloc(sizeof(UiToolbarItem));\r
     item->item.type = UI_TOOLBAR_ITEM;\r
-    item->args = itemargs_copy(args, &item->ngroups, &item->nvstates);\r
+    item->args = itemargs_copy(args, &item->nstates, &item->nvstates);\r
     cxMapPut(toolbar_items, name, item);\r
 }\r
 \r
@@ -78,15 +78,15 @@ static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args
     newargs.varname = nl_strdup(args->varname);\r
     newargs.onchange = args->onchange;\r
     newargs.onchangedata = args->onchangedata;\r
-    newargs.groups = uic_copy_groups(args->groups, ngroups);\r
-    newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\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
 void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args) {\r
     UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem));\r
     item->item.type = UI_TOOLBAR_TOGGLEITEM;\r
-    item->args = toggleitemargs_copy(args, &item->ngroups, &item->nvstates);\r
+    item->args = toggleitemargs_copy(args, &item->nstates, &item->nvstates);\r
     cxMapPut(toolbar_items, name, item);\r
 }\r
 \r
@@ -95,7 +95,7 @@ static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args, size_t *nvstates
     newargs.label = nl_strdup(args->label);\r
     newargs.icon = nl_strdup(args->icon);\r
     newargs.tooltip = nl_strdup(args->tooltip);\r
-    newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\r
+    newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
     return newargs;\r
 }\r
 \r
index 1ac1d553759fa14936bb1751429d81584a188462..9ae60f07cb5b0c04a0cd70b2ae0bcd70441ae49f 100644 (file)
@@ -62,14 +62,14 @@ struct UiToolbarItemI {
 struct UiToolbarItem {\r
     UiToolbarItemI item;\r
     UiToolbarItemArgs args;\r
-    size_t ngroups;\r
+    size_t nstates;\r
     size_t nvstates;\r
 };\r
 \r
 struct UiToolbarToggleItem {\r
     UiToolbarItemI item;\r
     UiToolbarToggleItemArgs args;\r
-    size_t ngroups;\r
+    size_t nstates;\r
     size_t nvstates;\r
 };\r
 \r
index 57ad68ee7ca9321d8530d769045eb4bf785095d4..e8680b785f4de29de1cf801b663ece55ab241923 100644 (file)
 
 #include <cx/list.h>
 #include <cx/array_list.h>
-#include "../ui/tree.h"
+#include "../ui/list.h"
 #include "types.h"
 #include "context.h"
 #include "../ui/image.h"
 
 static ui_list_init_func default_list_init;
 static void *default_list_init_userdata;
+static ui_list_destroy_func default_list_destroy;
+static void *default_list_destroy_userdata;
 
 UiObserver* ui_observer_new(ui_callback f, void *data) {
     UiObserver *observer = malloc(sizeof(UiObserver));
@@ -105,6 +107,11 @@ void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
     list->count = ui_list_count;
 }
 
+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) {
     return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata);
 }
@@ -121,9 +128,13 @@ UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listini
     return list;
 }
 
-void ui_list_free(UiList *list) {
-    cxListFree(list->data);
-    free(list);
+void ui_list_free(UiContext *ctx, UiList *list) {
+    if(!default_list_destroy) {
+        uic_ucx_list_destroy(ctx, list, NULL);
+    } else {
+        default_list_destroy(ctx, list, default_list_destroy_userdata);
+    }
+    
 }
 
 void* ui_list_first(UiList *list) {
@@ -201,6 +212,7 @@ typedef struct {
 
 UiModel* ui_model(UiContext *ctx, ...) {
     UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
+    info->ctx = ctx;
     
     va_list ap;
     va_start(ap, ctx);
@@ -240,8 +252,18 @@ UiModel* ui_model(UiContext *ctx, ...) {
 
 #define UI_MODEL_DEFAULT_ALLOC_SIZE 16
 
+
+static void model_notify_observer(UiModel *model, int insert, int delete) {
+    UiModelChangeObserver *obs = model->observer;
+    while(obs) {
+        obs->update(model, obs->userdata, insert, delete);
+        obs = obs->next;
+    }
+}
+
 UiModel* ui_model_new(UiContext *ctx) {
     UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
+    info->ctx = ctx;
     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*));
@@ -249,16 +271,21 @@ UiModel* ui_model_new(UiContext *ctx) {
     return info;
 }
 
-void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width) {
+void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width) {
+    UiContext *ctx = model->ctx;
     if(model->columns >= model->alloc) {
         model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE;
         model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType));
         model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*));
         model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int));
     }
-    model->types[model->columns] = type;
-    model->titles[model->columns] = ui_strdup(ctx, title);
-    model->columnsize[model->columns] = width;
+    int index = model->columns;
+    model->types[index] = type;
+    model->titles[index] = ui_strdup(ctx, title);
+    model->columnsize[index] = width;
+    
+    model_notify_observer(model, index, -1);
+    
     model->columns++;
 }
 
@@ -266,6 +293,7 @@ UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
     const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
 
     UiModel* newmodel = cxMalloc(a, sizeof(UiModel));
+    newmodel->ctx = ctx;
     *newmodel = *model;
 
     newmodel->types = cxCalloc(a, model->columns, sizeof(UiModelType));
@@ -281,11 +309,67 @@ UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
     return newmodel;
 }
 
-void ui_model_free(UiContext *ctx, UiModel *mi) {
-    const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
+void ui_model_ref(UiModel *model) {
+    model->ref++;
+}
+
+void ui_model_unref(UiModel *model) { 
+    if(--model->ref == 0) {
+        ui_model_free(model);
+    }
+}
+
+void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data) {
+    UiModelChangeObserver *observer = ui_malloc(model->ctx, sizeof(UiModelChangeObserver));
+    observer->update = update;
+    observer->userdata = data;
+    observer->next = NULL;
+    
+    if(model->observer) {
+        UiModelChangeObserver *last = model->observer;
+        while(last->next) {
+            last = last->next;
+        }
+        last->next = observer;
+    } else {
+        model->observer = observer;
+    }
+}
+
+void ui_model_remove_observer(UiModel *model, void *data) {
+    if(model->observer) {
+        UiModelChangeObserver *obs = model->observer;
+        UiModelChangeObserver *prev = NULL;
+        while(obs) {
+            if(obs->userdata == data) {
+                // remove
+                if(prev) {
+                    prev->next = obs->next;
+                } else {
+                    model->observer = obs->next;
+                }
+                // free
+                ui_free(model->ctx, obs);
+                break;
+            }
+            prev = obs;
+            obs = obs->next;
+        }
+    }
+}
+
+void ui_model_free(UiModel *mi) {
+    UiContext *ctx = mi->ctx;
+    const CxAllocator* a = ctx->allocator;
     for(int i=0;i<mi->columns;i++) {
         ui_free(ctx, mi->titles[i]);
     }
+    UiModelChangeObserver *obs = mi->observer;
+    while(obs) {
+        UiModelChangeObserver *n = obs->next;
+        cxFree(a, obs);
+        obs = n;
+    }
     cxFree(a, mi->types);
     cxFree(a, mi->titles);
     cxFree(a, mi->columnsize);
@@ -724,9 +808,7 @@ UIEXPORT void ui_list_setselection(UiList *list, int index) {
 }
 
 UIEXPORT void ui_listselection_free(UiListSelection selection) {
-    if (selection.rows) {
-        free(selection.rows);
-    }
+    free(selection.rows);
 }
 
 UIEXPORT UiStr ui_str(char *cstr) {
@@ -787,6 +869,7 @@ void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObser
 }
 
 static int ui_set_op = 0;
+static int ui_onchange_events_enabled = TRUE;
 
 void ui_setop_enable(int set) {
     ui_set_op = set;
@@ -796,6 +879,14 @@ int ui_get_setop(void) {
     return ui_set_op;
 }
 
+void ui_onchange_events_enable(UiBool enable) {
+    ui_onchange_events_enabled = enable;
+}
+
+UiBool ui_onchange_events_is_enabled(void) {
+    return ui_onchange_events_enabled;
+}
+
 /* ---------------- List initializers and wrapper functions ---------------- */
 
 void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
@@ -803,6 +894,11 @@ void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
     default_list_init_userdata = userdata;
 }
 
+void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) {
+    default_list_destroy = func;
+    default_list_destroy_userdata = userdata;
+}
+
 void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
     list->first = first;
 }
index 46d6c2e2f11a35f7890f9ffb13bf8159924758c6..2f4a5249ea8bd3e53de2e1f5608c2ba2e4054e35 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 #endif
     
 void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused);
+void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused);
     
 void uic_int_copy(UiInteger *from, UiInteger *to);
 void uic_double_copy(UiDouble *from, UiDouble *to);
diff --git a/ui/common/utils.c b/ui/common/utils.c
new file mode 100644 (file)
index 0000000..8d3b5dd
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 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 "utils.h"
+#include "properties.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <cx/string.h>
+#include <cx/buffer.h>
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) {
+    cxstring *pathelms;
+    size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms);
+
+    if (nelm == 0) {
+        *ret_nelm = 0;
+        return NULL;
+    }
+
+    UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm));
+    size_t n = nelm;
+    int j = 0;
+    for (int i = 0; i < nelm; i++) {
+        cxstring c = pathelms[i];
+        if (c.length == 0) {
+            if (i == 0) {
+                c.length = 1;
+            }
+            else {
+                n--;
+                continue;
+            }
+        }
+
+        cxmutstr m = cx_strdup(c);
+        elms[j].name = m.ptr;
+        elms[j].name_len = m.length;
+        
+        size_t elm_path_len = c.ptr + c.length - full_path;
+        cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
+        elms[j].path = elm_path.ptr;
+        elms[j].path_len = elm_path.length;
+
+        j++;
+    }
+    *ret_nelm = n;
+
+    return elms;
+}
+
+void ui_get_window_default_width(int *width, int *height) {
+    const char *width_str = ui_get_property("ui.window.width");
+    const char *height_str = ui_get_property("ui.window.height");
+    if(width_str && height_str) {
+        int w = atoi(width_str);
+        int h = atoi(height_str);
+        if(w > 0 && h > 0) {
+            *width = w;
+            *height = h;
+        }
+    }
+}
+
+// from UCX json.c
+static cxmutstr escape_string(cxstring str, bool escape_slash) {
+    // note: this function produces the string without enclosing quotes
+    // the reason is that we don't want to allocate memory just for that
+    CxBuffer buf = {0};
+
+    bool all_printable = true;
+    for (size_t i = 0; i < str.length; i++) {
+        unsigned char c = str.ptr[i];
+        bool escape = c < 0x20 || c == '\\' || c == '"'
+            || (escape_slash && c == '/');
+
+        if (all_printable && escape) {
+            size_t capa = str.length + 32;
+            char *space = cxMallocDefault(capa);
+            if (space == NULL) return cx_mutstrn(NULL, 0);
+            cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND);
+            cxBufferWrite(str.ptr, 1, i, &buf);
+            all_printable = false;
+        }
+        if (escape) {
+            cxBufferPut(&buf, '\\');
+            if (c == '\"') {
+                cxBufferPut(&buf, '\"');
+            } else if (c == '\n') {
+                cxBufferPut(&buf, 'n');
+            } else if (c == '\t') {
+                cxBufferPut(&buf, 't');
+            } else if (c == '\r') {
+                cxBufferPut(&buf, 'r');
+            } else if (c == '\\') {
+                cxBufferPut(&buf, '\\');
+            } else if (c == '/') {
+                cxBufferPut(&buf, '/');
+            } else if (c == '\f') {
+                cxBufferPut(&buf, 'f');
+            } else if (c == '\b') {
+                cxBufferPut(&buf, 'b');
+            } else {
+                char code[6];
+                snprintf(code, sizeof(code), "u%04x", (unsigned int) c);
+                cxBufferPutString(&buf, code);
+            }
+        } else if (!all_printable) {
+            cxBufferPut(&buf, c);
+        }
+    }
+    cxmutstr ret;
+    if (all_printable) {
+        // don't copy the string when we don't need to escape anything
+        ret = cx_mutstrn((char*)str.ptr, str.length);
+    } else {
+        ret = cx_mutstrn(buf.space, buf.size);
+    }
+    cxBufferDestroy(&buf);
+    return ret;
+}
+
+cxmutstr ui_escape_string(cxstring str) {
+    return escape_string(str, FALSE);
+}
diff --git a/ui/common/utils.h b/ui/common/utils.h
new file mode 100644 (file)
index 0000000..94f3e89
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 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_UTILS_H
+#define UIC_UTILS_H
+
+#include "../ui/toolkit.h"
+#include "../ui/text.h"
+
+#include <cx/string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data);
+
+/*
+ * overrides width/height with values from
+ * ui.window.width and ui.window.height properties if available
+ */
+void ui_get_window_default_width(int *width, int *height);
+
+cxmutstr ui_escape_string(cxstring str);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_UTILS_H */
+
index 50ecf407f9e15928741a8e9d857de6cd26f768f8..575dd2989f65b13ddec22503fd89ad0c612f3947 100644 (file)
@@ -125,6 +125,11 @@ void ui_srclist_remove(UiList *list, int index) {
     cxListRemove(cxlist, index);
 }
 
+void ui_srclist_swap(UiList *list, int i1, int i2) {
+    CxList *cxlist = list->data;
+    cxListSwap(cxlist, i1, i2);
+}
+
 void ui_srclist_clear(UiList *list) {
     CxList *cxlist = list->data;
     cxListClear(cxlist);
index 88fd8c813b538aabd1100b85c8fa0d7103ae748c..37f2f38a9f4de88d7dc584e2b178a5bc0bac1b57 100644 (file)
@@ -30,7 +30,7 @@
 #define UIC_WRAPPER_H
 
 #include "../ui/toolkit.h"
-#include "../ui/tree.h"
+#include "../ui/list.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -56,6 +56,7 @@ UIEXPORT UiList* ui_srclist_new(UiContext *ctx, const char *name);
 UIEXPORT void ui_srclist_add(UiList *list, UiSubList *item);
 UIEXPORT void ui_srclist_insert(UiList *list, int index, UiSubList *item);
 UIEXPORT void ui_srclist_remove(UiList *list, int index);
+UIEXPORT void ui_srclist_swap(UiList *list, int i1, int i2);
 UIEXPORT void ui_srclist_clear(UiList *list);
 UIEXPORT int ui_srclist_size(UiList *list);
 UIEXPORT void ui_srclist_generate_sublist_num_data(UiList *list);
index 6db5141b63ee8d714bb50c44b64fce5ad06a33ac..cf911cffbd865b4b70f5ea77dee0127e4b8b8e58 100644 (file)
@@ -106,7 +106,7 @@ GtkWidget* ui_create_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);
     ui_set_name_and_style(button, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, button, args->groups);
+    ui_set_widget_states(obj->ctx, button, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, button, &layout);
@@ -174,9 +174,9 @@ static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
 
 static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) {
     if(gtk_toggle_button_get_active(widget)) {
-        ui_set_group(event->obj->ctx, event->value);
+        ui_set_state(event->obj->ctx, event->value);
     } else {
-        ui_unset_group(event->obj->ctx, event->value);
+        ui_unset_state(event->obj->ctx, event->value);
     }
 }
 
@@ -308,9 +308,9 @@ static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleAr
             args->value,
             args->onchange,
             args->onchangedata,
-            args->enable_group);
+            args->enable_state);
     ui_set_name_and_style(widget, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, widget, args->groups);
+    ui_set_widget_states(obj->ctx, widget, args->states);
     
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
@@ -351,9 +351,9 @@ static void ui_checkbox_callback(GtkCheckButton *widget, UiEventData *event) {
 
 static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event) {
     if(gtk_check_button_get_active(widget)) {
-        ui_set_group(event->obj->ctx, event->value);
+        ui_set_state(event->obj->ctx, event->value);
     } else {
-        ui_unset_group(event->obj->ctx, event->value);
+        ui_unset_state(event->obj->ctx, event->value);
     }
 }
 
@@ -370,10 +370,10 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
             args->onchange,
             args->onchangedata,
             (ui_toggled_func)ui_checkbox_enable_state,
-            args->enable_group);
+            args->enable_state);
     
     ui_set_name_and_style(widget, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, widget, args->groups);
+    ui_set_widget_states(obj->ctx, widget, args->states);
     
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
@@ -419,7 +419,7 @@ static void switch_changed(
 UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
     GtkWidget *widget = gtk_switch_new();
     ui_set_name_and_style(widget, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, widget, args->groups);
+    ui_set_widget_states(obj->ctx, widget, args->states);
     
     UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
     if(var) {
@@ -541,7 +541,7 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
     
     GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args->label); 
     ui_set_name_and_style(rbutton, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, rbutton, args->groups);
+    ui_set_widget_states(obj->ctx, rbutton, args->states);
     if(rgroup) {
 #if GTK_MAJOR_VERSION >= 4
         if(rg) {
@@ -895,7 +895,7 @@ UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args) {
     }
     
     ui_set_name_and_style(button, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, button, args->groups);
+    ui_set_widget_states(obj->ctx, button, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, button, &layout);
index 9ca07f959e0883c2adb962ed6b2ea44b64cecc91..a8df7e8c338a972ab7801b68b2d413674cc47d42 100644 (file)
@@ -112,6 +112,21 @@ GtkWidget* ui_subcontainer_create(
     return add;
 }
 
+/* -------------------- Custom Container -------------------- */
+
+void ui_custom_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+    UiCustomContainer *custom = (UiCustomContainer*)ct;
+    custom->add(custom->obj, ct->widget, widget, custom->userdata);
+}
+
+void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_func add_child, void *userdata) {
+    UiCustomContainer *container = cxZalloc(obj->ctx->allocator, sizeof(UiCustomContainer));
+    container->container.add = ui_custom_container_add;
+    container->container.widget = widget;
+    container->add = add_child;
+    container->userdata = userdata;
+    uic_object_push_container(obj, (UiContainerX*)container);
+}
 
 /* -------------------- Box Container -------------------- */
 UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
@@ -985,6 +1000,8 @@ void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLay
             GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
             hb->centerbox = box;
             UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box);
+            UI_HEADERBAR_SHOW_TITLE_WIDGET(ct->widget, TRUE);
+            UI_HEADERBAR_SETTINGS(ct->widget);
         }
         BOX_ADD(hb->centerbox, widget);
     }
@@ -1140,6 +1157,7 @@ UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
 
 UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init) {
     UiSplitPane *ct = malloc(sizeof(UiSplitPane));
+    memset(ct, 0, sizeof(UiSplitPane));
     ct->current_pane = pane;
     ct->orientation = orientation;
     ct->max = max;
index 2f2510c51a3a505fc66400d71aeef7e80dd46f6e..f224aadd0736034a28f4cedd8c2c9581e83dff10 100644 (file)
@@ -61,6 +61,13 @@ struct UiContainerPrivate {
     int close;
 };
 
+typedef struct UiCustomContainer {
+    UiContainerPrivate container;
+    UiObject *obj;
+    ui_addwidget_func add;
+    void *userdata;
+} UiCustomContainer;
+
 typedef struct UiBoxContainer {
     UiContainerPrivate container;
     UiSubContainerType type;
index b411191cae49057d08a708463a81d830c608cf7a..9e61e4e109b40f09e4877381cf7966bf84ab32d2 100644 (file)
@@ -79,7 +79,7 @@ UIWIDGET ui_spinbox_create(UiObject *obj, UiSpinBoxArgs *args) {
 #endif
     GtkWidget *spin = gtk_spin_button_new_with_range(min, max, args->step);
     ui_set_name_and_style(spin, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, spin, args->groups);
+    ui_set_widget_states(obj->ctx, spin, args->states);
     
     if(args->width > 0) {
         gtk_widget_set_size_request(spin, args->width, -1);
index 33fd186ae63c885f8f9fa8c7192d0ef2148ee496..3ae10256ffe353e88e20d49662568c63063df37e 100644 (file)
@@ -107,14 +107,14 @@ UIWIDGET ui_drawingarea_create(UiObject *obj, UiDrawingAreaArgs *args) {
             widget,
             "draw",
             G_CALLBACK(draw_callback),
-            NULL);
+            drawingarea);
 #endif
     
     g_signal_connect(
-                widget,
-                "destroy",
-                G_CALLBACK(destroy_drawingarea),
-                drawingarea);
+            widget,
+            "destroy",
+            G_CALLBACK(destroy_drawingarea),
+            drawingarea);
     
     return widget;
 }
index 0a9bd3e7adc51de04a44ad02a61f2979f6b826f9..ef1d9c7e151fa79cf0203d2906eb32dab19031b0 100644 (file)
@@ -164,7 +164,7 @@ void ui_add_headerbar_item(
         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);
-    ui_set_widget_groups(obj->ctx, button, item->args.groups);
+    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);
@@ -178,7 +178,7 @@ void ui_add_headerbar_toggleitem(
         enum UiToolbarPos pos)
 {
     GtkWidget *button = gtk_toggle_button_new();
-    ui_set_widget_groups(obj->ctx, button, item->args.groups);
+    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);
index 93028ea515f7cbfac7aa9f6645b8de64540e5b83..392eae7fb581045a5e9cfe7fd3d88dcba864fa8e 100644 (file)
@@ -46,15 +46,20 @@ extern "C" {
 #define UI_HEADERBAR_PACK_START(h, w) adw_header_bar_pack_start(ADW_HEADER_BAR(h), w)
 #define UI_HEADERBAR_PACK_END(h, w) adw_header_bar_pack_end(ADW_HEADER_BAR(h), w)
 #define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) adw_header_bar_set_title_widget(ADW_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) adw_header_bar_set_show_title(ADW_HEADER_BAR(h), b)
+#define UI_HEADERBAR_SETTINGS(h) adw_header_bar_set_centering_policy(ADW_HEADER_BAR(h), ADW_CENTERING_POLICY_LOOSE)
 #else
 #define UI_HEADERBAR GtkHeaderBar*
 #define UI_HEADERBAR_CAST(h) GTK_HEADER_BAR(h)
 #define UI_HEADERBAR_PACK_START(h, w) gtk_header_bar_pack_start(GTK_HEADER_BAR(h), w)
 #define UI_HEADERBAR_PACK_END(h, w) gtk_header_bar_pack_end(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SETTINGS(h)
 #if GTK_MAJOR_VERSION >= 4
 #define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_title_widget(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) gtk_header_bar_set_show_title(GTK_HEADER_BAR(h), b)
 #else
 #define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_custom_title(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) gtk_header_bar_set_show_title(GTK_HEADER_BAR(h), b)
 #endif
 #endif
     
index e60dbdd46deaca14043eff25cefaa765d7294ea2..8181126301707af9236baa3e9d096c49920f1f79 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "container.h"
 #include "menu.h"
+#include "widget.h"
 #include "../common/context.h"
 #include "../common/object.h"
 
@@ -67,8 +68,14 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
     GtkWidget *drawingarea = gtk_drawing_area_new();
     GtkWidget *toplevel;
     GtkWidget *widget = drawingarea;
-      
-    gtk_widget_set_size_request(drawingarea, 100, 100);
+    
+    int width = args->width;
+    int height = args->height;
+    if(width == 0 && height == 0) {
+        width = 100;
+        height = 100;
+    }
+    ui_widget_size_request(drawingarea, width, height);
     
 #if GTK_MAJOR_VERSION < 4
     GtkWidget *eventbox = gtk_event_box_new();
index f793b2ca8634f7ddb1f030023f008efa937e6d0f..7a08ffccd764f455e4073c58bbb6648dce901eb4 100644 (file)
@@ -80,6 +80,7 @@ static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
     memset(tableview, 0, sizeof(UiListView));
     tableview->obj = obj;
     tableview->model = args->model;
+    tableview->multiselection = args->multiselection;
     tableview->onactivate = args->onactivate;
     tableview->onactivatedata = args->onactivatedata;
     tableview->onselection = args->onselection;
@@ -98,6 +99,11 @@ static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
     tableview->onsave = args->onsave;
     tableview->onsavedata = args->onsavedata;
     
+#if GTK_CHECK_VERSION(4, 0, 0)
+    tableview->coldata.listview = tableview;
+    tableview->coldata.column = 0;
+#endif
+    
     if(args->getvalue2) {
         tableview->getvalue = args->getvalue2;
         tableview->getvaluedata = args->getvalue2data;
@@ -200,7 +206,7 @@ static void cell_entry_activate(
 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
     UiColData *col = userdata;
     UiModel *model = col->listview->model;
-    UiModelType type = model->types[col->model_column];
+    UiModelType type = model->types[col->column];
     if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
         GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
         GtkWidget *image = gtk_image_new();
@@ -281,16 +287,17 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
     UiColData *col = userdata;
     UiList *list = col->listview->var ? col->listview->var->value : NULL;
     UiListView *listview = col->listview;
+    int datacolumn = listview->columns[col->column];
      
     ObjWrapper *obj = gtk_list_item_get_item(item);
     UiModel *model = col->listview->model;
-    UiModelType type = model->types[col->model_column];
+    UiModelType type = model->types[col->column];
     
     // cache the GtkListItem
     CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
     UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
     if(row) {
-        if(row->items[col->model_column] == NULL) {
+        if(row->items[col->column] == NULL) {
             row->bound++;
         }
     } else {
@@ -298,10 +305,10 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
         cxMapPut(listview->bound_rows, row_key, row);
         row->bound = 1;
     }
-    row->items[col->model_column] = item;
+    row->items[col->column] = item;
     
     UiBool freevalue = FALSE;
-    void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
+    void *data = listview->getvalue(list, obj->data, obj->i, datacolumn, listview->getvaluedata, &freevalue);
     GtkWidget *child = gtk_list_item_get_child(item);
     
     PangoAttrList *attributes = NULL;
@@ -319,7 +326,7 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
             }
         }
         
-        int style_col = col->data_column;
+        int style_col = datacolumn;
         if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
             style_col++; // col->data_column is the icon, we need the next col for the label
         }
@@ -363,7 +370,7 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
             
         }
         case UI_ICON_TEXT_FREE: {
-            void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue);
+            void *data2 = listview->getvalue(list, obj->data, obj->i, datacolumn+1, listview->getvaluedata, &freevalue);
             if(type == UI_ICON_TEXT_FREE) {
                 freevalue = TRUE;
             }
@@ -387,7 +394,7 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
             if(entry) {
                 entry->listview = col->listview;
                 entry->row = obj->i;
-                entry->col = col->data_column;
+                entry->col = datacolumn;
                 entry->previous_value = strdup(data);
             }
             ENTRY_SET_TEXT(child, data);
@@ -405,13 +412,13 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g
     }
 }
 
-static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
+static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {  
     ObjWrapper *obj = gtk_list_item_get_item(item);
     UiListView *listview = col->listview;
     CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
     UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
     if(row) {
-        row->items[col->model_column] = NULL;
+        row->items[col->column] = NULL;
         row->bound--;
         if(row->bound == 0) {
             cxMapRemove(listview->bound_rows, row_key);
@@ -457,17 +464,16 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     }
     
     listview->numcolumns = 1;
-    listview->columns = malloc(sizeof(UiColData));
-    listview->columns->listview = listview;
-    listview->columns->data_column = 0;
-    listview->columns->model_column = 0;
+    listview->columns = malloc(sizeof(int));
+    listview->columns[0] = 0;
     
     listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
     listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
      
     GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
-    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
-    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
+    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
+    g_signal_connect(factory, "unbind", G_CALLBACK(column_factory_unbind), &listview->coldata);
     
     GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
     GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
@@ -540,7 +546,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     return scroll_area;
 }
 
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
+UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
     // to simplify things and share code with ui_tableview_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
@@ -554,17 +560,15 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
     }
     
     listview->numcolumns = 1;
-    listview->columns = malloc(sizeof(UiColData));
-    listview->columns->listview = listview;
-    listview->columns->data_column = 0;
-    listview->columns->model_column = 0;
+    listview->columns = malloc(sizeof(int));
+    listview->columns[0] = 0;
     
     listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
     listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
     
     GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
-    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
-    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
+    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
     
     GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
     gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
@@ -591,8 +595,8 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
         
         list->obj = listview;
         list->update = ui_listview_update2;
-        list->getselection = ui_combobox_getselection;
-        list->setselection = ui_combobox_setselection;
+        list->getselection = ui_dropdown_getselection;
+        list->setselection = ui_dropdown_setselection;
         
         ui_update_liststore(ls, list);
     } else if (args->static_elements && args->static_nelm > 0) {
@@ -619,10 +623,34 @@ void ui_listview_select(UIWIDGET listview, int index) {
     gtk_selection_model_select_item(model, index, TRUE);
 }
     
-void ui_combobox_select(UIWIDGET dropdown, int index) {
+void ui_dropdown_select(UIWIDGET dropdown, int index) {
     gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
 }
 
+static void add_column(UiListView *tableview, int index) {
+    UiModel *model = tableview->model;
+    
+    UiColData *col = malloc(sizeof(UiColData));
+    col->listview = tableview;
+    col->column = index;
+    
+    GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
+    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
+    g_object_set_data_full(G_OBJECT(factory), "coldata", col, (GDestroyNotify)free);
+
+    GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[index], factory);
+    gtk_column_view_column_set_resizable(column, true);
+    gtk_column_view_insert_column(GTK_COLUMN_VIEW(tableview->widget), index, column);
+
+    int size = model->columnsize[index];
+    if(size > 0) {
+        gtk_column_view_column_set_fixed_width(column, size);
+    } else if(size < 0) {
+        gtk_column_view_column_set_expand(column, TRUE);
+    }
+}
+
 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     //g_list_store_append(ls, v1);
@@ -650,9 +678,13 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     
     // create columns from UiModel
     UiModel *model = args->model;
-    int columns = model ? model->columns : 0;
+    int columns = 0;
+    if(model) {
+        columns = model->columns;
+        ui_model_add_observer(model, ui_listview_update_model, tableview);
+    }
     
-    tableview->columns = calloc(columns, sizeof(UiColData));
+    tableview->columns = calloc(columns, sizeof(int));
     tableview->numcolumns = columns;
     
     tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
@@ -660,30 +692,14 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     
     int addi = 0;
     for(int i=0;i<columns;i++) {
-        tableview->columns[i].listview = tableview;
-        tableview->columns[i].model_column = i;
-        tableview->columns[i].data_column = i+addi;
+        tableview->columns[i] = i+addi;
         
         if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
             // icon+text has 2 data columns
             addi++;
         }
         
-        GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
-        UiColData *col = &tableview->columns[i]; 
-        g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
-       g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
-        
-        GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[i], factory);
-        gtk_column_view_column_set_resizable(column, true);
-        gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column);
-        
-        int size = model->columnsize[i];
-        if(size > 0) {
-            gtk_column_view_column_set_fixed_width(column, size);
-        } else if(size < 0) {
-            gtk_column_view_column_set_expand(column, TRUE);
-        }
+        add_column(tableview, i);
     }
     
     // bind listview to list
@@ -734,6 +750,49 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     return scroll_area;
 }
 
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index) {
+    UiListView *listview = userdata;
+    if(insert_index >= listview->numcolumns) {
+        listview->numcolumns = insert_index+1;
+        listview->columns = realloc(listview->columns, listview->numcolumns * sizeof(UiColData));
+    }
+    
+    gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), NULL);
+    cxMapClear(listview->bound_rows);
+    
+    if(insert_index) {
+        int prev = 0;
+        if(insert_index > 0) {
+            prev = listview->columns[insert_index-1];
+        }
+        listview->columns[insert_index] = prev+1;
+        add_column(listview, insert_index);
+        
+        if(insert_index+1 < listview->numcolumns) {
+            // the data index of trailing columns must be adjusted
+            UiModelType type = model->types[insert_index];
+            int add = 1;
+            if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+                add++;
+            }
+            for(int i=insert_index+1;i<listview->numcolumns;i++) {
+                listview->columns[i] += add;
+            }
+        }
+    } // TODO: delete_index
+    
+    GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
+    GtkSelectionModel *selection_model = create_selection_model(listview, ls, listview->multiselection);
+    gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), selection_model);
+    listview->selectionmodel = selection_model;
+    listview->liststore = ls;
+    
+    if(listview->var) {
+        UiList *list = listview->var->value;
+        ui_list_update(list);
+    }
+}
+
 static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
     UiListSelection sel = { 0, NULL };
     GtkBitset *bitset = gtk_selection_model_get_selection(model);
@@ -860,7 +919,9 @@ void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm)
 
 void ui_listview_update2(UiList *list, int i) {
     UiListView *view = list->obj;
+    view->current_row = -1;
     if(i < 0) {
+        cxMapClear(view->bound_rows);
         ui_update_liststore(view->liststore, list);
     } else {
         void *value = list->get(list, i);
@@ -873,9 +934,12 @@ void ui_listview_update2(UiList *list, int i) {
             CxHashKey row_key = cx_hash_key(&i, sizeof(int));
             UiRowItems *row = cxMapGet(view->bound_rows, row_key);
             if(row) {
+                UiColData coldata;
+                coldata.listview = view;
                 for(int c=0;c<view->numcolumns;c++) {
                     if(row->items[c] != NULL) {
-                        column_factory_bind(NULL, row->items[c], &view->columns[c]);
+                        coldata.column = c;
+                        column_factory_bind(NULL, row->items[c], &coldata);
                     }
                 }
             }
@@ -915,7 +979,7 @@ void ui_listview_setselection2(UiList *list, UiListSelection selection) {
     ui_setop_enable(FALSE);
 }
 
-UiListSelection ui_combobox_getselection(UiList *list) {
+UiListSelection ui_dropdown_getselection(UiList *list) {
     UiListView *view = list->obj;
     guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget));
     UiListSelection sel = { 0, NULL };
@@ -927,7 +991,7 @@ UiListSelection ui_combobox_getselection(UiList *list) {
     return sel;
 }
 
-void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
     ui_setop_enable(TRUE);
     UiListView *view = list->obj;
     if(selection.count > 0) {
@@ -1156,7 +1220,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     ui_set_name_and_style(view, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, view, args->groups);
+    ui_set_widget_states(obj->ctx, view, args->states);
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
     gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
@@ -1272,7 +1336,7 @@ void ui_listview_select(UIWIDGET listview, int index) {
     //g_object_unref(path);
 }
     
-void ui_combobox_select(UIWIDGET dropdown, int index) {
+void ui_dropdown_select(UIWIDGET dropdown, int index) {
     gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
 }
 
@@ -1514,16 +1578,16 @@ void ui_listview_setselection(UiList *list, UiListSelection selection) {
 
 
 
-/* --------------------------- ComboBox ---------------------------  */
+/* --------------------------- Dropdown ---------------------------  */
 
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
+UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
     GtkWidget *combobox = gtk_combo_box_new();
     if(args->width > 0) {
         gtk_widget_set_size_request(combobox, args->width, -1);
     }
     
     ui_set_name_and_style(combobox, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, combobox, args->groups);
+    ui_set_widget_states(obj->ctx, combobox, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, combobox, &layout);
@@ -1544,8 +1608,8 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
     if(var) {
         listview->var = var;
         list->update = ui_combobox_modelupdate;
-        list->getselection = ui_combobox_getselection;
-        list->setselection = ui_combobox_setselection;
+        list->getselection = ui_dropdown_getselection;
+        list->setselection = ui_dropdown_setselection;
         list->obj = listview;
         list->update(list, -1);
     } else if(args->static_nelm > 0) {
@@ -1622,7 +1686,7 @@ void ui_combobox_modelupdate(UiList *list, int i) {
     g_object_unref(store);
 }
 
-UiListSelection ui_combobox_getselection(UiList *list) {
+UiListSelection ui_dropdown_getselection(UiList *list) {
     UiListView *combobox = list->obj;
     UiListSelection ret;
     ret.rows = malloc(sizeof(int*));
@@ -1631,7 +1695,7 @@ UiListSelection ui_combobox_getselection(UiList *list) {
     return ret;
 }
 
-void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
     ui_setop_enable(TRUE);
     UiListView *combobox = list->obj;
     if(selection.count > 0) {
@@ -2045,6 +2109,10 @@ void ui_listview_destroy(GtkWidget *w, UiListView *v) {
     if(v->var) {
         ui_destroy_boundvar(v->obj->ctx, v->var);
     }
+    if(v->model) {
+        ui_model_remove_observer(v->model, v);
+        ui_model_unref(v->model);
+    }
     if(v->elements) {
         for(int i=0;i<v->nelm;i++) {
             free(v->elements[i]);
@@ -2160,6 +2228,8 @@ static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *subli
         UiList *list = uisublist.var->value;
         list->obj = sublist_ptr;
         list->update = ui_listbox_list_update;
+        list->getselection = ui_listbox_list_getselection;
+        list->setselection = ui_listbox_list_setselection;
     }
 }
 
@@ -2181,7 +2251,7 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
     SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
     
     ui_set_name_and_style(listbox, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, listbox, args->groups);
+    ui_set_widget_states(obj->ctx, listbox, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, scroll_area, &layout);
@@ -2223,6 +2293,8 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
             UiList *list = var->value;
             list->obj = uilistbox;
             list->update = ui_listbox_dynamic_update;
+            list->getselection = ui_listbox_dynamic_getselection;
+            list->setselection = ui_listbox_dynamic_setselection;
             
             ui_listbox_dynamic_update(list, -1);
         }
@@ -2294,6 +2366,32 @@ void ui_listbox_dynamic_update(UiList *list, int x) {
     ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
 }
 
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel) {
+    UiListBox *uilistbox = list->obj;
+    gtk_list_box_unselect_all(uilistbox->listbox);
+    if(sel.count > 0) {
+        int index = sel.rows[0];
+        if(index >= 0) {
+            GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, index);
+            if(row) {
+                gtk_list_box_select_row(uilistbox->listbox, row);
+            }
+        }
+    }
+}
+
+UiListSelection ui_listbox_dynamic_getselection(UiList *list) {
+    UiListSelection sel = { 0, NULL };
+    UiListBox *uilistbox = list->obj;
+    GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+    if(row) {
+        sel.count = 1;
+        sel.rows = malloc(sizeof(int));
+        sel.rows[0] = gtk_list_box_row_get_index(row);
+    }
+    return sel;
+}
+
 void ui_listbox_update(UiListBox *listbox, int from, int to) {
     CxIterator i = cxListIterator(listbox->sublists);
     size_t pos = 0;
@@ -2659,6 +2757,39 @@ void ui_listbox_list_update(UiList *list, int i) {
     ui_sourcelist_update_finished();
 }
 
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel) {
+    UiListBoxSubList *sublist = list->obj;
+    UiListBox *uilistbox = sublist->listbox;
+    gtk_list_box_unselect_all(uilistbox->listbox);
+    if(sel.count > 0) {
+        int index = sel.rows[0];
+        if(index >= 0 && index < sublist->numitems) {
+            int global_index = sublist->startpos + index;
+            GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, global_index);
+            if(row) {
+                gtk_list_box_select_row(uilistbox->listbox, row);
+            }
+        }
+    }
+}
+
+UiListSelection ui_listbox_list_getselection(UiList *list) {
+    UiListSelection sel = { 0, NULL };
+    UiListBoxSubList *sublist = list->obj;
+    UiListBox *uilistbox = sublist->listbox;
+    GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+    if(row) {
+        int index = gtk_list_box_row_get_index(row);
+        size_t startpos = sublist->startpos;
+        if(index >= startpos && index < startpos+sublist->numitems) {
+            sel.count = 1;
+            sel.rows = malloc(sizeof(int));
+            sel.rows[0] = index - startpos;
+        }
+    }
+    return sel;
+}
+
 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
     UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata");
     if(!data) {
index 1aaf89bd7adaebf1a4f9f7157248886eaccbfee4..ef828d47131e48aeeb34dff6950a7aaa6aba9ac8 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef TREE_H
-#define        TREE_H
+#ifndef LIST_H
+#define        LIST_H
 
-#include "../ui/tree.h"
+#include "../ui/list.h"
 #include "toolkit.h"
 
 #include <cx/array_list.h>
@@ -38,6 +38,7 @@
 extern "C" {
 #endif
     
+typedef struct UiListView UiListView;
 typedef struct UiColData UiColData;
 
 #if GTK_CHECK_VERSION(4, 10, 0)
@@ -47,11 +48,17 @@ typedef struct UiRowItems {
 } UiRowItems;
 #endif
 
-typedef struct UiListView {
+struct UiColData {
+    UiListView *listview;
+    int column;
+};
+
+struct UiListView {
     UiObject          *obj;
     GtkWidget         *widget;
     UiVar             *var;
     UiModel           *model;
+    UiBool            multiselection;
     ui_getvaluefunc2  getvalue;
     void              *getvaluedata;
     ui_getstylefunc   getstyle;
@@ -65,8 +72,9 @@ typedef struct UiListView {
     CxMap             *bound_rows;
     GListStore        *liststore;
     GtkSelectionModel *selectionmodel;
-    UiColData         *columns;
+    int               *columns;
     int               numcolumns;
+    UiColData         coldata;
     PangoAttrList     *current_row_attributes;
 #else
     int               style_offset;
@@ -85,12 +93,6 @@ typedef struct UiListView {
     void              *onsavedata;
     UiListSelection   selection;
     
-} UiListView;
-
-struct UiColData {
-    UiListView *listview;
-    int model_column;
-    int data_column;
 };
 
 typedef struct UiTreeEventData {
@@ -136,6 +138,7 @@ struct UiListBox {
 void ui_update_liststore(GListStore *liststore, UiList *list);
 void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm);
 
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index);
 void ui_listview_update2(UiList *list, int i);
 UiListSelection ui_listview_getselection2(UiList *list);
 void ui_listview_setselection2(UiList *list, UiListSelection selection);
@@ -155,6 +158,7 @@ UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks
 
 GtkWidget* ui_get_tree_widget(UIWIDGET widget);
 
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index);
 void ui_listview_update(UiList *list, int i);
 UiListSelection ui_listview_getselection(UiList *list);
 void ui_listview_setselection(UiList *list, UiListSelection selection);
@@ -186,13 +190,18 @@ UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui
 GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata);
 void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e);
 void ui_combobox_modelupdate(UiList *list, int i);
-UiListSelection ui_combobox_getselection(UiList *list);
-void ui_combobox_setselection(UiList *list, UiListSelection selection);
+UiListSelection ui_dropdown_getselection(UiList *list);
+void ui_dropdown_setselection(UiList *list, UiListSelection selection);
 
 void ui_listbox_dynamic_update(UiList *list, int i);
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_dynamic_getselection(UiList *list);
+
 void ui_listbox_update(UiListBox *listbox, int from, int to);
 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index);
 void ui_listbox_list_update(UiList *list, int i);
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_list_getselection(UiList *list);
 
 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data);
         
@@ -200,5 +209,5 @@ void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user
 }
 #endif
 
-#endif /* TREE_H */
+#endif /* LIST_H */
 
index 74597ae6462f5ffdea62f85ce0471a1c9b2e8ee4..44d32ca4989e6b7a97131a582b65bb3140f9e3e6 100644 (file)
@@ -129,11 +129,11 @@ void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObje
     
     gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
     
-    if(i->groups) {
-        CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
-        cxListAddArray(groups, i->groups, i->ngroups);
-        uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
-        cxListFree(groups);
+    if(i->states) {
+        CxList *states = cxArrayListCreateSimple(sizeof(int), i->nstates);
+        cxListAddArray(states, i->states, i->nstates);
+        uic_add_state_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, states);
+        cxListFree(states);
     }
 }
 
@@ -462,10 +462,10 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
     g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
     g_object_unref(action);
     
-    if(i->groups) {
-        CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
-        cxListAddArray(groups, i->groups, i->ngroups);
-        uic_add_group_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups);
+    if(i->states) {
+        CxList *groups = cxArrayListCreateSimple(sizeof(int), i->nstates);
+        cxListAddArray(groups, i->states, i->nstates);
+        uic_add_state_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups);
         cxListFree(groups);
     }
     
index 085964278b1b93527d7c7f92580d4e1e88187526..cb52e4a90363a8191180552512ca4ac26e8bf7e9 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "text.h"
 #include "container.h"
+#include "widget.h"
 
 #include <cx/printf.h>
 
@@ -53,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_group(textview->ctx, UI_GROUP_SELECTION);
+                ui_set_state(textview->ctx, UI_GROUP_SELECTION);
             } else {
-                ui_unset_group(textview->ctx, UI_GROUP_SELECTION);
+                ui_unset_state(textview->ctx, UI_GROUP_SELECTION);
             }
         }
         textview->last_selection_state = sel;
@@ -112,7 +113,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
     
     GtkWidget *text_area = gtk_text_view_new();
     ui_set_name_and_style(text_area, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, text_area, args->groups);
+    ui_set_widget_states(obj->ctx, text_area, args->states);
     
     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR);
     g_signal_connect(
@@ -144,17 +145,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area);
     
-    if(args->width > 0 || args->height > 0) {
-        int width = args->width;
-        int height = args->height;
-        if(width == 0) {
-            width = -1;
-        }
-        if(height == 0) {
-            height = -1;
-        }
-        gtk_widget_set_size_request(scroll_area, width, height);
-    }
+    ui_widget_size_request(scroll_area, args->width, args->height);
     
     // font and padding
     //PangoFontDescription *font;
@@ -335,6 +326,10 @@ void ui_textarea_realize_event(GtkWidget *widget, gpointer data) {
 
 
 void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
+    if(!ui_onchange_events_is_enabled()) {
+        return;
+    }
+    
     UiText *value = textarea->var->value;
     
     UiEvent e;
@@ -608,7 +603,7 @@ void ui_text_redo(UiText *value) {
 static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs *args) {
     GtkWidget *textfield = gtk_entry_new();
     ui_set_name_and_style(textfield, args->name, args->style_class);
-    ui_set_widget_groups(obj->ctx, textfield, args->groups);
+    ui_set_widget_states(obj->ctx, textfield, args->states);
     
     UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     
@@ -698,14 +693,18 @@ void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) {
 }
 
 void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
-    UiString *value = textfield->var->value;
+    if(!ui_onchange_events_is_enabled()) {
+        return;
+    }
+    
+    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 = UI_EVENT_DATA_TEXT_VALUE;
+    e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
     e.intval = 0;
     e.set = ui_get_setop();
     
@@ -720,12 +719,14 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
 
 void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
     if(textfield->onactivate) {
+        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 = NULL;
-        e.eventdatatype = 0;
+        e.eventdata = value;
+        e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
         e.intval = 0;
         e.set = ui_get_setop();
         textfield->onactivate(&e, textfield->onactivatedata);
@@ -956,6 +957,10 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
     pathtf->stack = gtk_stack_new();
     gtk_widget_set_name(pathtf->stack, "path-textfield-box");
     
+    if(args->width > 0) {
+        gtk_widget_set_size_request(pathtf->stack, args->width, -1);
+    }
+    
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, pathtf->stack, &layout);
@@ -1127,6 +1132,10 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
             G_CALLBACK(ui_path_textfield_destroy),
             pathtf);
     
+    if(args->width > 0) {
+        gtk_widget_set_size_request(eventbox, args->width, -1);
+    }
+    
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, eventbox, &layout);
index 64b221ab7307bd8f529f55cda6c81442ffd37e5c..0e195ff9046cd28482e2805d0c9f77aa5575e11d 100644 (file)
@@ -139,7 +139,7 @@ void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) {
     }
     gtk_tool_item_set_is_important(button, TRUE);
     
-    ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups);
+    ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates);
     
     if(item->args.onclick) {
         UiEventData *event = cxMalloc(
@@ -181,7 +181,7 @@ void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObj
     if(item->args.tooltip) {
         gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), item->args.tooltip);
     }
-    ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups);
+    ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates);
     
     UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER);
     if(var) {
@@ -394,7 +394,7 @@ void add_headerbar_item_widget(GtkHeaderBar *hb, UiToolbarItem *item, UiObject *
     if(item->args.icon) {
         ui_button_set_icon_name(button, item->args.icon);
     }
-    ui_set_widget_groups(obj->ctx, button, item->args.groups);
+    ui_set_widget_states(obj->ctx, button, item->args.states);
     
     gtk_header_bar_pack_start(hb, button);
     
index 87d1ef1240d3b61b9556356fd268ef4c05ad7e77..e0a30c2ab697c4f535db78eb41a87f76c3413bba 100644 (file)
@@ -39,6 +39,7 @@
 #include "../common/menu.h"
 #include "../common/toolbar.h"
 #include "../common/threadpool.h"
+#include "../common/app.h"
 
 #include <cx/string.h>
 #include <cx/printf.h>
@@ -51,13 +52,6 @@ UI_APPLICATION app;
 
 static const char *application_name;
 
-static ui_callback   startup_func;
-static void          *startup_data;
-static ui_callback   open_func;
-void                 *open_data;
-static ui_callback   exit_func;
-void                 *exit_data;
-
 static ui_callback   appclose_fnc;
 static void          *appclose_udata;
 
@@ -95,30 +89,13 @@ const char* ui_appname() {
     return application_name;
 }
 
-void ui_onstartup(ui_callback f, void *userdata) {
-    startup_func = f;
-    startup_data = userdata;
-}
-
-void ui_onopen(ui_callback f, void *userdata) {
-    open_func = f;
-    open_data = userdata;
-}
-
-void ui_onexit(ui_callback f, void *userdata) {
-    exit_func = f;
-    exit_data = userdata;
-}
-
 void ui_app_exit_on_shutdown(UiBool exitapp) {
     exit_on_shutdown = exitapp;
 }
 
 #ifdef UI_APPLICATION
 static void app_startup(GtkApplication* app, gpointer userdata) {
-    if(startup_func) {
-        startup_func(NULL, startup_data);
-    }
+    uic_application_startup(NULL);
 }
 
 static void app_activate(GtkApplication* app, gpointer userdata) {
@@ -126,9 +103,7 @@ static void app_activate(GtkApplication* app, gpointer userdata) {
 }
 
 static void app_shutdown(GtkApplication *app, gpointer userdata) {
-    if(exit_func) {
-        exit_func(NULL, exit_data);
-    }
+    uic_application_exit(NULL);
     ui_app_save_settings();
 }
 
@@ -148,13 +123,9 @@ void ui_main() {
     
     free(appid.ptr);
 #else
-    if(startup_func) {
-        startup_func(NULL, startup_data);
-    }
+    uic_application_startup(NULL);
     gtk_main();
-    if(exit_func) {
-        exit_func(NULL, exit_data);
-    }
+    uic_application_exit(NULL);
     ui_app_save_settings();
 #endif
     if(exit_on_shutdown) {
@@ -164,7 +135,7 @@ void ui_main() {
 
 #ifndef UI_GTK2
 void ui_app_quit() {
-    g_application_quit(G_APPLICATION(app));
+    g_application_quit(G_APPLICATION(app)); // TODO: fix, does not work
 }
 
 GtkApplication* ui_get_application() {
@@ -175,7 +146,7 @@ GtkApplication* ui_get_application() {
 void ui_show(UiObject *obj) {
     gboolean visible = gtk_widget_is_visible(obj->widget);
     
-    uic_check_group_widgets(obj->ctx);
+    uic_check_state_widgets(obj->ctx);
 #if GTK_MAJOR_VERSION >= 4
     gtk_window_present(GTK_WINDOW(obj->widget));
 #elif GTK_MAJOR_VERSION <= 3
@@ -263,14 +234,14 @@ void ui_set_show_all(UIWIDGET widget, int value) {
 #endif
 }
 
-void ui_set_visible(UIWIDGET widget, int visible) {
+void ui_set_visible(UIWIDGET widget, UiBool visible) {
 #if GTK_MAJOR_VERSION >= 4
     gtk_widget_set_visible(widget, visible);
 #else
     if(visible) {
-        gtk_widget_set_no_show_all(widget, FALSE);
         gtk_widget_show_all(widget);
     } else {
+        gtk_widget_set_no_show_all(widget, FALSE);
         gtk_widget_hide(widget);
     }
 #endif
@@ -346,6 +317,11 @@ UiObject *ui_get_active_window() {
 
 #if GTK_MAJOR_VERSION == 4
 static const char *ui_gtk_css = 
+".ui-entry-box {\n"
+"  background-color: alpha(currentColor, 0.1);"
+"  border-radius: 6px;"
+"  padding: 7px;"
+"}\n"
 "#path-textfield-box {\n"
 "  background-color: alpha(currentColor, 0.1);"
 "  border-radius: 6px;"
@@ -529,17 +505,17 @@ void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *styl
     }
 }
 
-void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups) {
-    if(!groups) {
+void ui_set_widget_states(UiContext *ctx, GtkWidget *widget, const int *states) {
+    if(!states) {
         return;
     }
-    size_t ngroups = uic_group_array_size(groups);
-    ui_set_widget_ngroups(ctx, widget, groups, ngroups);
+    size_t nstates = uic_state_array_size(states);
+    ui_set_widget_nstates(ctx, widget, states, nstates);
 }
 
-void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups) {
-    if(ngroups > 0) {
-        uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups);
+void ui_set_widget_nstates(UiContext *ctx, GtkWidget *widget, const int *states, size_t nstates) {
+    if(nstates > 0) {
+        uic_add_state_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, states, nstates);
         ui_set_enabled(widget, FALSE);
     }
 }
@@ -548,14 +524,14 @@ void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const in
     if(!states) {
         return;
     }
-    size_t nstates = uic_group_array_size(states);
+    size_t nstates = uic_state_array_size(states);
     ui_set_widget_nvisibility_states(ctx, widget, states, nstates);
 }
 
 
 void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups) {
     if(ngroups > 0) {
-        uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_visible, states, ngroups);
+        uic_add_state_widget_i(ctx, widget, (ui_enablefunc)ui_set_visible, states, ngroups);
         ui_set_visible(widget, FALSE);
     }
 }
index cfa25bb34e23fbb5e282e8abdd8fe7cf2dee1ac9..8d1ee573e5ad881b911077538004ba5ae5e555d3 100644 (file)
@@ -178,8 +178,8 @@ GtkApplication* ui_get_application();
 int ui_get_scalefactor();
 
 void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style);
-void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups);
-void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups);
+void ui_set_widget_states(UiContext *ctx, GtkWidget *widget, const int *states);
+void ui_set_widget_nstates(UiContext *ctx, GtkWidget *widget, const int *states, size_t nstates);
 void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const int *states);
 void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
 
index f8f57185a091be6a607b389c0bbba4f567742266..6a1f319f5add611c0bb94789570812d9788509f7 100644 (file)
@@ -30,6 +30,7 @@
 #include "container.h"
 
 #include "webview.h"
+#include "widget.h"
 
 #ifdef UI_WEBVIEW
 
@@ -38,6 +39,8 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
     
     ui_set_name_and_style(webview, args->name, args->style_class);
     
+    ui_widget_size_request(webview, args->width, args->height);
+    
     UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
     if(var) {
         WebViewData *data = malloc(sizeof(WebViewData));
@@ -57,7 +60,7 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
         }
     }
     
-    ui_set_widget_groups(obj->ctx, webview, args->groups);
+    ui_set_widget_states(obj->ctx, webview, args->states);
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
     UiLayout layout = UI_ARGS2LAYOUT(args);
     ct->add(ct, webview, &layout);
index 06ef1b2406395fd91e7c168aca136329c48b2dd2..95cbb121c75e34d95b402c541ebd03b905d5156e 100644 (file)
 
 #include "../common/object.h"
 
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
+void ui_widget_size_request(UIWIDGET w, int width, int height) {
+    if(width > 0 || height > 0) {
+        if(width == 0) {
+            width = -1;
+        }
+        if(height == 0) {
+            height = -1;
+        }
+        gtk_widget_set_size_request(w, width, height);
+    }
+}
+
+
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
     UIWIDGET widget = create_widget(obj, args, userdata);
     
     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
index 57c7314d3cc2fe91290817fd6092b73a36e74a23..7ee6ed4704f7003aa4c7b94b2303280f6050c30d 100644 (file)
 extern "C" {
 #endif
 
-
+/*
+ * Sets a widget width/height.
+ * 
+ * If wdith or height is 0, the dimension is not changed
+ */
+void ui_widget_size_request(UIWIDGET w, int width, int height);
 
 
 #ifdef __cplusplus
index f90997f32e39ba9f380bf021389de9ee05fe7820..2081de29c9879278d47a7eb95fdc8dc0bc9185fb 100644 (file)
@@ -35,6 +35,7 @@
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/toolbar.h"
+#include "../common/utils.h"
 
 #include <cx/mempool.h>
 
@@ -141,7 +142,7 @@ static void save_window_splitview_pos(GtkWidget *widget, void *unused) {
     ui_set_property("ui.window.splitview.pos", buf);
 }
 
-static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool splitview, UiBool simple) {
+static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitview, UiBool simple) {
     UiObject *obj = uic_object_new_toplevel();
    
 #ifdef UI_LIBADWAITA
@@ -152,8 +153,6 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
     obj->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 #endif
     
-    obj->window = window_data;
-    
 #if GTK_CHECK_VERSION(4, 0, 0)
     obj->ctx->action_map = G_ACTION_MAP(obj->widget);
 #endif
@@ -169,16 +168,7 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
     int window_width = window_default_width;
     int window_height = window_default_height;
     if(!simple) {
-        const char *width = ui_get_property("ui.window.width");
-        const char *height = ui_get_property("ui.window.height");
-        if(width && height) {
-            int w = atoi(width);
-            int h = atoi(height);
-            if(w > 0 && h > 0) {
-                window_width = w;
-                window_height = h;
-            }
-        }
+        ui_get_window_default_width(&window_width, &window_height);
     }
     gtk_window_set_default_size(
                 GTK_WINDOW(obj->widget),
@@ -205,6 +195,21 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
             obj);
 #endif
     
+    int splitview_pos = 0;
+    if(splitview) {
+        const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos");
+        splitview_pos= splitview_window_default_pos;
+        if(splitview_pos < 0) {
+            splitview_pos = window_width / 2;
+        }
+        if(splitview_pos_str && splitview_window_use_prop) {
+            int sv_pos = atoi(splitview_pos_str);
+            if(sv_pos > 0) {
+                splitview_pos = sv_pos;
+            }
+        }
+    }
+    
     GtkWidget *vbox = ui_gtk_vbox_new(0);
 #ifdef UI_LIBADWAITA
     GtkWidget *toolbar_view = adw_toolbar_view_new();
@@ -223,18 +228,7 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
                 G_CALLBACK(save_window_splitview_pos),
                 NULL);
         
-        const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos");
-        int pos = splitview_window_default_pos;
-        if(pos < 0) {
-            pos = window_width / 2;
-        }
-        if(splitview_pos_str && splitview_window_use_prop) {
-            int splitview_pos = atoi(splitview_pos_str);
-            if(splitview_pos > 0) {
-                pos = splitview_pos;
-            }
-        }
-        gtk_paned_set_position(GTK_PANED(content), pos);
+        gtk_paned_set_position(GTK_PANED(content), splitview_pos);
         
         GtkWidget *right_panel = adw_toolbar_view_new();
         GtkWidget *right_vbox = ui_gtk_vbox_new(0);
@@ -345,14 +339,32 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
     
     GtkWidget *content_box = ui_gtk_vbox_new(0);
     WINDOW_SET_CONTENT(obj->widget, vbox);
-    if(sidebar) {
+    if(sidebar || splitview) {
         GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
-        GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0);
-        gtk_paned_add1(GTK_PANED(paned), sidebar_vbox);
-        gtk_paned_add2(GTK_PANED(paned), content_box);
+        if(sidebar) {
+            GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0);
+            gtk_paned_add1(GTK_PANED(paned), sidebar_vbox);
+            g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox);
+            gtk_paned_set_position(GTK_PANED(paned), 200);
+        }
+        
+        if(splitview) {
+            GtkWidget *content_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+            gtk_paned_set_position(GTK_PANED(content_paned), splitview_pos);
+            gtk_paned_add2(GTK_PANED(paned), content_paned);
+            
+            GtkWidget *right_content_box = ui_gtk_vbox_new(0);
+            gtk_paned_add1(GTK_PANED(content_paned), content_box);
+            gtk_paned_add2(GTK_PANED(content_paned), right_content_box);
+            
+            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);
+        } else {
+            gtk_paned_add2(GTK_PANED(paned), content_box);
+        }
+        
         BOX_ADD_EXPAND(GTK_BOX(vbox), paned);
-        g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox);
-        gtk_paned_set_position (GTK_PANED(paned), 200);
     } else {
         BOX_ADD_EXPAND(GTK_BOX(vbox), content_box);
     }
@@ -380,20 +392,20 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
 }
 
 
-UiObject* ui_window(const char *title, void *window_data) {
-    return create_window(title, window_data, FALSE, FALSE, FALSE);
+UiObject* ui_window(const char *title) {
+    return create_window(title, FALSE, FALSE, FALSE);
 }
 
-UiObject *ui_sidebar_window(const char *title, void *window_data) {
-    return create_window(title, window_data, TRUE, FALSE, FALSE);
+UiObject *ui_sidebar_window(const char *title) {
+    return create_window(title, TRUE, FALSE, FALSE);
 }
 
-UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
-    return create_window(title, NULL, sidebar, TRUE, FALSE);
+UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
+    return create_window(title, sidebar, TRUE, FALSE);
 }
 
-UiObject* ui_simple_window(const char *title, void *window_data) {
-    return create_window(title, window_data, FALSE, FALSE, TRUE);
+UiObject* ui_simple_window(const char *title) {
+    return create_window(title, FALSE, FALSE, TRUE);
 }
 
 void ui_window_size(UiObject *obj, int width, int height) {
index 693f7309fed15e57102ce35046091eee4d5c131f..55367f19fc7e54e34c09738c469edf0fbaf91ce5 100644 (file)
@@ -65,7 +65,7 @@ typedef struct UiButtonArgs {
     ui_callback onclick;
     void *onclickdata;
     
-    const int *groups;
+    const int *states;
 } UiButtonArgs;
 
 typedef struct UiToggleArgs {
@@ -93,9 +93,9 @@ typedef struct UiToggleArgs {
     const char *varname;
     ui_callback onchange;
     void *onchangedata;
-    int enable_group;
+    int enable_state;
     
-    const int *groups;
+    const int *states;
 } UiToggleArgs;
 
 typedef struct UiLinkButtonArgs {
@@ -124,7 +124,7 @@ typedef struct UiLinkButtonArgs {
     UiBool nofollow;
     UiLinkType type;
     
-    const int *groups;
+    const int *states;
 } UiLinkButtonArgs;
  
 #define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } )
index 3355850cbb0ea9b3a1679ac667abd30b5c956b37..dc2aa299ebef95b7e26fc502c1edbb28bd58bffc 100644 (file)
@@ -98,6 +98,8 @@ typedef struct UiFrameArgs {
     int margin_bottom;
     int colspan;
     int rowspan;
+    int width;
+    int height;
     const char *name;
     const char *style_class;
 
@@ -310,13 +312,14 @@ struct UiContainerX {
 #define ui_left_panel0(obj) for(ui_left_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_right_panel0(obj) for(ui_right_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
 
-
 #define ui_vbox_w(obj, w, ...) for(w = ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 
+#define ui_custom_container(ob, widget, addfunc, data) for(ui_custom_container_create(obj, widget, addfunc, data);ui_container_finish(obj);ui_container_begin_close(obj))
+
 #define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
 #define ui_hsplitpane0(obj) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
@@ -367,6 +370,9 @@ UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBo
 
 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);
index 6dd6a0a5983572a16aa4810db9c6887c5d8b2dc2..9ee26d3b1e5a02cab83240cb61febc84ba55b7c1 100644 (file)
@@ -65,7 +65,7 @@ typedef struct UiSpinBoxArgs {
     ui_callback onchange;
     void* onchangedata;
     
-    const int *groups;
+    const int *states;
 } UiSpinBoxArgs;
 
 
index 77d923fe49967317f353aafb84a41067399e4989..0730f7569d6bacd06c1d1b889146c955f6afbebe 100644 (file)
@@ -58,6 +58,8 @@ typedef struct UiImageViewerArgs {
     int margin_bottom;
     int colspan;
     int rowspan;
+    int width;
+    int height;
     const char *name;
     const char *style_class;
 
similarity index 85%
rename from ui/ui/tree.h
rename to ui/ui/list.h
index 33a903c06196df279a8d87a2c6005bc1700c06f0..b4d0e0af9f3819ae46a6f47e6f3ead9b1b9dcea8 100644 (file)
@@ -67,7 +67,18 @@ typedef struct UiCellValue {
 
 typedef UiBool (*ui_list_savefunc)(UiList *list, int row, int col, UiCellValue *value, void *userdata);
 
+typedef void (*ui_model_update_func)(UiModel *model, void *userdata, int insert_index, int delete_index);
+
+typedef struct UiModelChangeObserver UiModelChangeObserver;
+struct UiModelChangeObserver {
+    ui_model_update_func update;
+    void *userdata;
+    UiModelChangeObserver *next;
+};
+
 struct UiModel {
+    UiContext *ctx;
+    
     /*
      * number of columns
      */
@@ -94,6 +105,17 @@ struct UiModel {
      * array of column size hints
      */
     int *columnsize;
+    
+    /*
+     * Model change observers, that will be called when
+     * columns are added or removed
+     */
+    UiModelChangeObserver *observer;
+    
+    /*
+     * reference counter
+     */
+    int ref;
 };
 
 struct UiListCallbacks {
@@ -132,9 +154,9 @@ struct UiListArgs {
 
     const char *name;
     const char *style_class;
-    UiListlist;
+    UiList *list;
     const char* varname;
-    UiModelmodel;
+    UiModel *model;
     char **static_elements;
     size_t static_nelm;
     ui_getvaluefunc getvalue;
@@ -143,21 +165,21 @@ struct UiListArgs {
     ui_getstylefunc getstyle;
     void *getstyledata;
     ui_callback onactivate;
-    voidonactivatedata;
+    void *onactivatedata;
     ui_callback onselection;
-    voidonselectiondata;
+    void *onselectiondata;
     ui_callback ondragstart;
-    voidondragstartdata;
+    void *ondragstartdata;
     ui_callback ondragcomplete;
-    voidondragcompletedata;
+    void *ondragcompletedata;
     ui_callback ondrop;
-    voidondropdata;
+    void *ondropdata;
     UiBool multiselection;
     UiMenuBuilder *contextmenu;
     ui_list_savefunc onsave;
     void *onsavedata;
     
-    const int *groups;
+    const int *states;
 };
 
 typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
@@ -213,7 +235,7 @@ struct UiSourceListArgs {
     const char *name;
     const char *style_class;
     
-    const int *groups;
+    const int *states;
     
     /*
      * static list of sublists
@@ -290,23 +312,27 @@ struct UiSourceListArgs {
  */
 UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
 UIEXPORT UiModel* ui_model_new(UiContext *ctx);
-UIEXPORT void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width);
+UIEXPORT void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width);
 UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
-UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
+UIEXPORT void ui_model_ref(UiModel *model);
+UIEXPORT void ui_model_unref(UiModel *model);
+UIEXPORT void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data);
+UIEXPORT void ui_model_remove_observer(UiModel *model, void *data);
+UIEXPORT void ui_model_free(UiModel *mi);
 
 #define ui_listview(obj, ...) ui_listview_create(obj, &(UiListArgs) { __VA_ARGS__ } )
 #define ui_table(obj, ...) ui_table_create(obj, &(UiListArgs) { __VA_ARGS__ } )
-#define ui_combobox(obj, ...) ui_combobox_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_dropdown(obj, ...) ui_dropdown_create(obj, &(UiListArgs) { __VA_ARGS__ } )
 #define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, &(UiListArgs) { __VA_ARGS__ } )
 #define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, &(UiSourceListArgs) { __VA_ARGS__ } )
 
-UIEXPORT UIWIDGET ui_listview_create(UiObjectobj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_table_create(UiObjectobj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObjectobj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject *obj, UiListArgs *args);
 
 UIEXPORT void ui_listview_select(UIWIDGET listview, int index);
-UIEXPORT void ui_combobox_select(UIWIDGET dropdown, int index);
+UIEXPORT void ui_dropdown_select(UIWIDGET dropdown, int index);
 
 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args);
 
index 9dde9b4546bca50c1b7d60793d8b009b06dedd1e..43cca7e7f6ab80e39a945356b0c8db06fb320f9e 100644 (file)
@@ -43,7 +43,7 @@ typedef struct UiMenuItemArgs {
        ui_callback onclick;
        void* onclickdata;
 
-       const int* groups;
+       const int* states;
 } UiMenuItemArgs;
 
 typedef struct UiMenuToggleItemArgs {
@@ -54,7 +54,7 @@ typedef struct UiMenuToggleItemArgs {
        ui_callback onchange;
        void* onchangedata;
 
-       const int* groups;
+       const int* nstates;
 } UiMenuToggleItemArgs;
 
 typedef struct UiMenuItemListArgs {
diff --git a/ui/ui/stock.h b/ui/ui/stock.h
deleted file mode 100644 (file)
index ab2d13d..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 UI_STOCK_H
-#define        UI_STOCK_H
-
-#include "toolkit.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// motif stock ids
-#if UI_MOTIF || UI_COCOA || UI_QT4 || UI_QT5
-    
-#define UI_STOCK_NEW                    "ui.stock.New"
-#define UI_STOCK_OPEN                   "ui.stock.Open"
-#define UI_STOCK_SAVE                   "ui.stock.Save"
-#define UI_STOCK_SAVE_AS                "ui.stock.SaveAs"
-#define UI_STOCK_REVERT_TO_SAVED        "ui.stock.RevertToSaved"
-#define UI_STOCK_GO_BACK                "ui.stock.GoBack"
-#define UI_STOCK_GO_FORWARD             "ui.stock.GoForward"
-#define UI_STOCK_ADD                    "ui.stock.Add"
-#define UI_STOCK_CLOSE                  "ui.stock.Close"
-    
-#define UI_STOCK_UNDO                   "ui.stock.Undo"
-#define UI_STOCK_REDO                   "ui.stock.Redo"
-#define UI_STOCK_CUT                    "ui.stock.Cut"
-#define UI_STOCK_COPY                   "ui.stock.Copy"
-#define UI_STOCK_PASTE                  "ui.stock.Paste"
-#define UI_STOCK_DELETE                 "ui.stock.Delete"
-    
-#endif
-    
-#if UI_GTK2 || UI_GTK3
-    
-#define UI_STOCK_NEW                    GTK_STOCK_NEW
-#define UI_STOCK_OPEN                   GTK_STOCK_OPEN
-#define UI_STOCK_SAVE                   GTK_STOCK_SAVE
-#define UI_STOCK_SAVE_AS                GTK_STOCK_SAVE_AS
-#define UI_STOCK_REVERT_TO_SAVED        GTK_STOCK_REVERT_TO_SAVED
-#define UI_STOCK_UNDO                   GTK_STOCK_UNDO
-#define UI_STOCK_REDO                   GTK_STOCK_REDO
-#define UI_STOCK_GO_BACK                GTK_STOCK_GO_BACK
-#define UI_STOCK_GO_FORWARD             GTK_STOCK_GO_FORWARD
-#define UI_STOCK_ADD                    GTK_STOCK_ADD
-#define UI_STOCK_CLOSE                  GTK_STOCK_CLOSE
-
-#define UI_STOCK_UNDO                   GTK_STOCK_UNDO
-#define UI_STOCK_REDO                   GTK_STOCK_REDO
-#define UI_STOCK_CUT                    GTK_STOCK_CUT
-#define UI_STOCK_COPY                   GTK_STOCK_COPY
-#define UI_STOCK_PASTE                  GTK_STOCK_PASTE
-#define UI_STOCK_DELETE                 GTK_STOCK_DELETE
-    
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UI_STOCK_H */
-
index ac5a2c1d3a16fb645fafbc08fea94e15f820e218..c102f0b36ce20b74160aa1b2494b599c099dd92c 100644 (file)
@@ -59,7 +59,7 @@ typedef struct UiTextAreaArgs {
     ui_callback onchange;
     void *onchangedata;
     
-    const int *groups;
+    const int *states;
 } UiTextAreaArgs;
     
 typedef struct UiTextFieldArgs {
@@ -87,7 +87,7 @@ typedef struct UiTextFieldArgs {
     ui_callback onactivate;
     void *onactivatedata;
     
-    const int *groups;
+    const int *states;
 } UiTextFieldArgs;
 
 typedef struct UiPathElmRet {
@@ -115,6 +115,7 @@ typedef struct UiPathTextFieldArgs {
     int margin_bottom;
     int colspan;
     int rowspan;
+    int width;
     const char *name;
     const char *style_class;
 
index 26a79e68e38a7a85265452fa7ca330b0f115d144..2e230df495810275d9a65fc0313a5ff40e05224e 100644 (file)
@@ -44,7 +44,7 @@ typedef struct UiToolbarItemArgs {
     ui_callback onclick;
     void* onclickdata;
 
-    const int *groups;
+    const int *states;
     const int *visibility_states;
 } UiToolbarItemArgs;
 
@@ -57,7 +57,7 @@ typedef struct UiToolbarToggleItemArgs {
     ui_callback onchange;
     void *onchangedata;
 
-    const int *groups;
+    const int *states;
     const int *visibility_states;
 } UiToolbarToggleItemArgs;
 
index 83cd78abc0df9becf116d93fd1634a9167f7d018..628e3e8907ec5f69efc13c490a1552bb677b1df0 100644 (file)
@@ -146,6 +146,14 @@ public:
 #endif
 
 
+#elif UI_SERVER
+
+typedef struct UiWidget UiWidget;
+
+#define UIWIDGET UiWidget*
+#define UIWINDOW UiWidget*
+#define UIMENU   void*
+
 #endif
 
 #ifndef TRUE
@@ -417,6 +425,7 @@ struct UiGeneric {
 };
     
 typedef void (*ui_list_init_func)(UiContext *ctx, UiList *list, void *userdata);
+typedef void (*ui_list_destroy_func)(UiContext *ctx, UiList *list, void *userdata);
 
 /*
  * abstract list
@@ -541,6 +550,7 @@ UIEXPORT int ui_app_save_settings(void);
 UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
 
 UIEXPORT void ui_main(void);
+UIEXPORT void ui_app_quit(void);
 UIEXPORT void ui_show(UiObject *obj);
 UIEXPORT void ui_close(UiObject *obj);
 
@@ -557,16 +567,18 @@ UIEXPORT void* ui_get_subdocument(void *document);               // deprecated
 
 UIEXPORT UiContext* ui_document_context(void *doc);
 
+UIEXPORT void* ui_context_get_document(UiContext *ctx);
+UIEXPORT void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable);
 UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
 UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
 
-UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
-UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups);
+UIEXPORT void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
+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_set_group(UiContext *ctx, int group);
-UIEXPORT void ui_unset_group(UiContext *ctx, int group);
-UIEXPORT int* ui_active_groups(UiContext *ctx, int *ngroups);
+UIEXPORT void ui_set_state(UiContext *ctx, int state);
+UIEXPORT void ui_unset_state(UiContext *ctx, int state);
+UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates);
     
 UIEXPORT void* ui_allocator(UiContext *ctx);
 UIEXPORT void* ui_cx_mempool(UiContext *ctx);
@@ -625,6 +637,13 @@ UIEXPORT double ui_var_get_double(UiContext *ctx, const char *name);
 UIEXPORT void ui_var_set_string(UiContext *ctx, const char *name, char *value);
 UIEXPORT char* ui_var_get_string(UiContext *ctx, const char *name);
 
+UIEXPORT UiInteger* ui_get_int_var(UiContext *ctx, const char *name);
+UIEXPORT UiDouble* ui_get_double_var(UiContext *ctx, const char *name);
+UIEXPORT UiString* ui_get_string_var(UiContext *ctx, const char *name);
+UIEXPORT UiText* ui_get_text_var(UiContext *ctx, const char *name);
+UIEXPORT UiRange* ui_get_range_var(UiContext *ctx, const char *name);
+UIEXPORT UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name);
+
 UIEXPORT UiObserver* ui_observer_new(ui_callback f, void *data);
 UIEXPORT UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer);
 UIEXPORT UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);
@@ -635,7 +654,7 @@ UIEXPORT void ui_notify_evt(UiObserver *observer, UiEvent *event);
 
 UIEXPORT UiList* ui_list_new(UiContext *ctx, const char *name);
 UIEXPORT UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func init, void *userdata);
-UIEXPORT void ui_list_free(UiList *list);
+UIEXPORT void ui_list_free(UiContext *ctx, UiList *list);
 UIEXPORT void* ui_list_first(UiList *list);
 UIEXPORT void* ui_list_next(UiList *list);
 UIEXPORT void* ui_list_get(UiList *list, int i);
@@ -680,9 +699,12 @@ UIEXPORT void ui_condvar_destroy(UiCondVar *var);
 
 UIEXPORT void ui_setop_enable(int set);
 UIEXPORT int ui_get_setop(void);
+UIEXPORT void ui_onchange_events_enable(UiBool enable);
+UIEXPORT UiBool ui_onchange_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_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));
@@ -690,6 +712,9 @@ UIEXPORT void ui_list_class_set_count(UiList *list, int(*count)(UiList *list));
 UIEXPORT void ui_list_class_set_data(UiList *list, void *data);
 UIEXPORT void ui_list_class_set_iter(UiList *list, void *iter);
 
+UIEXPORT void ui_object_set(UiObject *obj, const char *key, void *data);
+UIEXPORT void* ui_object_get(UiObject *obj, const char *key);
+
 #ifdef __cplusplus
 }
 #endif
index 57c802593c1b7b261ffbe242afd86a711789b6a2..472ca74dd4ffe36f15a2d5d5d7b82be7e975db1b 100644 (file)
 #include "menu.h"
 #include "toolbar.h"
 #include "window.h"
-#include "stock.h"
 #include "button.h"
 #include "text.h"
 #include "properties.h"
-#include "tree.h"
+#include "list.h"
 #include "graphics.h"
 #include "entry.h"
 #include "range.h"
index 9636165f22bda227e84245327b98bcd0512279a6..d5a243ddb9d48aca1ddb928e42684dde547952f1 100644 (file)
@@ -60,13 +60,15 @@ typedef struct UiWebviewArgs {
     int margin_bottom;
     int colspan;
     int rowspan;
+    int width;
+    int height;
     const char *name;
     const char *style_class;
     
     UiGeneric *value;
     const char *varname;
     
-    const int* groups;
+    const int* states;
 } UiWebviewArgs;
 
 #define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
index aea5b8eb3e7967276106c25b30be9667f7de0fa0..40503baa2fb88e61111eced55a096b768f5a4bc5 100644 (file)
@@ -64,6 +64,8 @@ typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void
 typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_WIN32)
 typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
+#elif defined(UI_SERVER)
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #endif
 UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args);
 
index 54d054349251be52b01c64f6f1c50e7ed6e0e6db..1137265ed9e36cea73f96da930af60bddd8c7a07 100644 (file)
@@ -49,7 +49,7 @@ struct W32Size {
 };\r
 \r
 struct W32WidgetClass {\r
-    void (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+    int (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
     void (*show)(W32Widget *widget, BOOLEAN show);\r
     void (*enable)(W32Widget *widget, BOOLEAN enable);\r
     W32Size (*get_preferred_size)(W32Widget *widget);\r
index 83e85a34dd3f65ec8b2d303f222134d7a4cd3b8b..d100016f225e77a3aad7c0d2da792bc8715ae513 100644 (file)
@@ -61,10 +61,10 @@ typedef struct UiDialogWindowArgs {
     const char *lbutton2;
     const char *rbutton3;
     const char *rbutton4;
-    const int *lbutton1_groups;
-    const int *lbutton2_groups;
-    const int *rbutton3_groups;
-    const int *rbutton4_groups;
+    const int *lbutton1_states;
+    const int *lbutton2_states;
+    const int *rbutton3_states;
+    const int *rbutton4_states;
     int default_button;
     int width;
     int height;
@@ -72,10 +72,10 @@ typedef struct UiDialogWindowArgs {
     void *onclickdata;
 } UiDialogWindowArgs;
 
-UIEXPORT UiObject *ui_window(const char *title, void *window_data);
-UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data);
+UIEXPORT UiObject *ui_window(const char *title);
+UIEXPORT UiObject *ui_sidebar_window(const char *title);
 UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar);
-UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data);
+UIEXPORT UiObject *ui_simple_window(const char *title);
 UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args);
 
 #define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ __VA_ARGS__ });
@@ -83,6 +83,9 @@ UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs
 
 UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
 UIEXPORT void ui_window_default_size(int width, int height);
+UIEXPORT void ui_window_menubar_set_visible(UiObject *obj, UiBool visible);
+
+UIEXPORT void ui_window_fullscreen(UiObject *obj, UiBool fullscreen);
 
 UIEXPORT void ui_splitview_window_set_pos(UiObject *obj, int pos);
 UIEXPORT int ui_splitview_window_get_pos(UiObject *obj);