# HG changeset patch
# User Olaf Wintermann
# Date 1753041879 -7200
# Node ID 77254bd6dccb7f43ddfa76e70c69dce931cc1f84
# Parent b34bd1557c6cfdc26092baad4e8991913a226591
update toolkit, adjust UI code
diff -r b34bd1557c6c -r 77254bd6dccb application/Makefile
--- a/application/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/application/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -45,10 +45,13 @@
OBJ = $(SRC:%.c=../build/application/%.$(OBJ_EXT))
+LIB_UCX = $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(LIB_EXT)
+LIB_UITK = $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
+
all: ../build/bin/idav$(APP_EXT)
-../build/bin/idav$(APP_EXT): $(OBJ)
- $(CC) -o ../build/bin/idav$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS)
+../build/bin/idav$(APP_EXT): $(OBJ) $(LIB_UCX) $(LIB_UITK)
+ $(CC) -o ../build/bin/idav$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(LIB_UCX) $(LIB_UITK)
../build/application/%.$(OBJ_EXT): %.c
$(CC) $(CFLAGS) $(TK_CFLAGS) $(DAV_CFLAGS) -o $@ -c $<
diff -r b34bd1557c6c -r 77254bd6dccb application/settings.c
--- a/application/settings.c Sat Apr 05 17:57:04 2025 +0200
+++ b/application/settings.c Sun Jul 20 22:04:39 2025 +0200
@@ -636,18 +636,18 @@
wdata->obj = obj;
settings_init(obj, wdata);
- ui_tabview(obj, .tabview = UI_TABVIEW_NAVIGATION_TOP) {
+ ui_tabview(obj, .tabview = UI_TABVIEW_NAVIGATION_TOP, .fill = TRUE) {
ui_tab(obj, "General") {
- ui_grid(obj, .margin = 10) {
+ ui_grid(obj, .margin = 10, .fill = TRUE) {
ui_label(obj, .label = "TODO");
}
}
ui_tab(obj, "Repositories") {
- ui_tabview(obj, .value = wdata->repo_tabview, .tabview = UI_TABVIEW_INVISIBLE) {
+ ui_tabview(obj, .value = wdata->repo_tabview, .tabview = UI_TABVIEW_INVISIBLE, .fill = TRUE) {
ui_tab(obj, "list") {
- ui_grid(obj, .margin = 16, .columnspacing = 10, .rowspacing = 10) {
+ ui_grid(obj, .margin = 16, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) {
ui_hbox(obj, .spacing = 4) {
ui_button(obj, .label = "Add", .onclick = repolist_add);
ui_button(obj, .label = "Edit", .onclick = repolist_edit, .groups = UI_GROUPS(SETTINGS_STATE_REPOLIST_SELECTED));
@@ -663,18 +663,19 @@
.multiselection = FALSE,
.onactivate = repolist_activate,
.onselection = repolist_selection,
- .vexpand = TRUE, .hexpand = TRUE, .colspan = 3);
+ .vexpand = TRUE, .hexpand = TRUE,
+ .hfill = TRUE, .vfill = TRUE, .colspan = 3);
}
}
ui_tab(obj, "repo") {
- ui_vbox(obj, .margin = 16, .spacing = 10) {
- ui_hbox(obj, .fill = UI_OFF, .spacing = 4) {
+ ui_vbox(obj, .margin = 16, .spacing = 10, .fill = TRUE) {
+ ui_hbox(obj, .spacing = 4) {
ui_button(obj, .icon = UI_ICON_GO_BACK, .onclick = editrepo_go_back);
ui_label(obj, .label = "Repository List");
}
- ui_scrolledwindow(obj, .hexpand = TRUE, .vexpand = TRUE, .subcontainer = UI_CONTAINER_NO_SUB) {
+ ui_scrolledwindow(obj, .subcontainer = UI_CONTAINER_NO_SUB, .fill = TRUE) {
ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10) {
ui_llabel(obj, .label = "Name");
ui_textfield(obj, .value = wdata->repo_name, .width = 15);
@@ -740,19 +741,19 @@
}
ui_tab(obj, "Sync Directories") {
- ui_grid(obj, .margin = 10) {
+ ui_grid(obj, .margin = 10, .fill = TRUE) {
ui_label(obj, .label = "TODO");
}
}
ui_tab(obj, "Credentials") {
- ui_hbox(obj, .margin = 16, .spacing = 30) {
- ui_vbox(obj, .fill = UI_OFF, .spacing = 4) {
- ui_hbox(obj, .fill = UI_OFF, .spacing = 4) {
+ ui_hbox(obj, .margin = 16, .spacing = 30, .fill = TRUE) {
+ ui_vbox(obj, .spacing = 4) {
+ ui_hbox(obj, .spacing = 4) {
ui_button(obj, .label = "Add", .onclick = credentials_add);
ui_button(obj, .label = "Remove", .onclick = credentials_remove, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED));
}
- ui_listview(obj, .list = wdata->credentials_users, .fill = UI_ON, .onselection = credentials_onselect);
+ ui_listview(obj, .list = wdata->credentials_users, .fill = TRUE, .onselection = credentials_onselect);
}
ui_grid(obj, .columnspacing = 30, .rowspacing = 10) {
@@ -783,8 +784,8 @@
#else
ui_callback credentials_activate_callback = NULL;
#endif
- ui_listview(obj, .list = wdata->credentials_locations, .onactivate = credentials_activate_callback, .onselection = credentials_location_onselect, .colspan = 2, .fill = UI_ON, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED));
- ui_vbox(obj, .fill = UI_OFF, .spacing = 4) {
+ ui_listview(obj, .list = wdata->credentials_locations, .onactivate = credentials_activate_callback, .onselection = credentials_location_onselect, .colspan = 2, .fill = TRUE, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED));
+ ui_vbox(obj, .spacing = 4) {
ui_button(obj, .label = "Add", .onclick = credentials_location_add, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED));
ui_button(obj, .label = "Edit", .onclick = credentials_location_edit, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
ui_button(obj, .label = "Remove", .onclick = credentials_location_remove, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
@@ -798,12 +799,12 @@
ui_tab(obj, "Keys") {
ui_hbox(obj, .margin = 16, .spacing = 30) {
- ui_vbox(obj, .fill = UI_OFF, .spacing = 4) {
- ui_hbox(obj, .fill = UI_OFF, .spacing = 4) {
+ ui_vbox(obj, .spacing = 4) {
+ ui_hbox(obj, .spacing = 4) {
ui_button(obj, .label = "Add", .onclick = keys_add);
ui_button(obj, .label = "Remove", .onclick = keys_remove, .groups = UI_GROUPS(SETTINGS_STATE_KEYS_SELECTED));
}
- ui_listview(obj, .list = wdata->keys_list, .fill = UI_ON, .onselection = keys_onselect, .getvalue = keylist_getvalue);
+ ui_listview(obj, .list = wdata->keys_list, .fill = TRUE, .onselection = keys_onselect, .getvalue = keylist_getvalue);
}
ui_grid(obj, .columnspacing = 30, .rowspacing = 10) {
@@ -828,9 +829,9 @@
*/
}
- ui_hbox(obj, .fill = UI_OFF, .margin = 10) {
+ ui_hbox(obj, .margin = 10) {
ui_button(obj, .label = "Cancel", .onclick = settings_cancel);
- ui_label(obj, .fill = UI_ON);
+ ui_label(obj, .fill = TRUE);
ui_button(obj, .label = "Save", .onclick = settings_ok);
}
diff -r b34bd1557c6c -r 77254bd6dccb application/window.c
--- a/application/window.c Sat Apr 05 17:57:04 2025 +0200
+++ b/application/window.c Sun Jul 20 22:04:39 2025 +0200
@@ -81,13 +81,13 @@
// navigation bar
- ui_hbox(obj, .fill = UI_OFF, .margin = 8, .spacing = 8) {
- ui_hbox(obj, .fill = UI_OFF, .style_class="linked") {
+ ui_hbox(obj, .margin = 8, .spacing = 8) {
+ ui_hbox(obj, .style_class="linked") {
ui_button(obj, .icon = UI_ICON_GO_BACK, .onclick = action_go_back);
ui_button(obj, .icon = UI_ICON_GO_FORWARD, .onclick = action_go_forward);
}
- ui_path_textfield(obj, .fill = UI_ON, .getpathelm = dav_get_pathelm, .onactivate = action_path_selected, .varname = "path");
+ ui_path_textfield(obj, .fill = TRUE, .getpathelm = dav_get_pathelm, .onactivate = action_path_selected, .varname = "path");
ui_progressspinner(obj, .value = wdata->progress);
}
@@ -97,7 +97,7 @@
model->columnsize[2] = 150;
model->getvalue = (ui_getvaluefunc) window_resource_table_getvalue;
ui_table(obj,
- .fill = UI_ON,
+ .fill = TRUE,
.model = model,
.onselection = action_list_selection,
.onactivate = action_list_activate,
@@ -110,7 +110,7 @@
// status bar
- ui_hbox(obj, .fill = UI_OFF) {
+ ui_hbox0(obj) {
ui_label(obj, .label = "");
}
@@ -199,10 +199,10 @@
ui_attach_document(win->ctx, doc);
ui_context_closefunc(win->ctx, resourceviewer_close, doc);
- ui_tabview(win, .tabview = UI_TABVIEW_INVISIBLE, .varname = "tabview") {
+ ui_tabview(win, .tabview = UI_TABVIEW_INVISIBLE, .varname = "tabview", .fill = TRUE) {
/* loading / message tab */
ui_tab(win, NULL) {
- ui_hbox(win, .margin = 16, .spacing = 10, .fill = UI_OFF) {
+ ui_hbox(win, .margin = 16, .spacing = 10, .fill = TRUE) {
ui_progressspinner(win, .varname = "loading");
ui_label(win, .varname = "message");
}
@@ -210,7 +210,7 @@
/* preview tab */
ui_tab(win, NULL) {
- ui_tabview0(win) {
+ ui_tabview(win, .fill = TRUE) {
if(type == DAV_RESOURCE_VIEW_TEXT) {
ui_tab(win, "Content") {
ui_textarea(win, .varname = "text", .onchange = action_resourceviewer_text_modified);
@@ -220,12 +220,13 @@
ui_imageviewer(win,
.varname = "image",
.scrollarea = TRUE,
- .useradjustable = TRUE);
+ .useradjustable = TRUE,
+ .fill = TRUE);
}
}
ui_tab(win, "Info") {
- ui_grid(win, .margin = 16, .columnspacing = 30, .rowspacing = 6) {
+ ui_grid(win, .margin = 16, .columnspacing = 30, .rowspacing = 6, .fill = TRUE) {
ui_llabel(win, .label = "URL");
ui_llabel(win, .varname = "info_url");
ui_newline(win);
@@ -255,8 +256,8 @@
ui_tab(win, "Properties") {
UiModel* model = ui_model(win->ctx, UI_STRING, "Namespace", UI_STRING, "Name", UI_STRING, "Value", -1);
model->getvalue = (ui_getvaluefunc) resourceviewer_proplist_getvalue;
- ui_table(win, .fill = UI_ON, .model = model, .varname = "properties", .onselection = action_resourceviewer_property_select, .onactivate = action_resourceviewer_property_activate);
- ui_hbox(win, .fill = UI_OFF, .margin = 4, .spacing = 4) {
+ ui_table(win, .fill = TRUE, .model = model, .varname = "properties", .onselection = action_resourceviewer_property_select, .onactivate = action_resourceviewer_property_activate);
+ ui_hbox(win, .margin = 4, .spacing = 4) {
ui_button(win, .label = "Add", .onclick = action_resourceviewer_property_add);
ui_button(win, .label = "Edit", .onclick = action_resourceviewer_property_edit, .groups = UI_GROUPS(RESOURCEVIEWER_STATE_PROP_SELECTED));
ui_button(win, .label = "Remove", .onclick = action_resourceviewer_property_remove, .groups = UI_GROUPS(RESOURCEVIEWER_STATE_PROP_SELECTED));
@@ -322,7 +323,7 @@
wdata->password = ui_string_new(obj->ctx, NULL);
obj->window = wdata;
- ui_grid(obj, .margin = 20, .columnspacing = 12, .rowspacing = 12) {
+ ui_grid(obj, .margin = 20, .columnspacing = 12, .rowspacing = 12, .fill = TRUE) {
cxmutstr heading = cx_asprintf("Authentication required for: %s", auth->sn->base_url);
ui_llabel(obj, .label = heading.ptr, .colspan = 2);
free(heading.ptr);
diff -r b34bd1557c6c -r 77254bd6dccb configure
--- a/configure Sat Apr 05 17:57:04 2025 +0200
+++ b/configure Sun Jul 20 22:04:39 2025 +0200
@@ -107,11 +107,11 @@
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
Build Types:
---debug add extra compile flags for debug builds
---release add extra compile flags for release builds
+ --debug add extra compile flags for debug builds
+ --release add extra compile flags for release builds
Options:
- --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|motif)
+ --toolkit=(libadwaita|gtk4|gtk3|cocoa|qt5|motif)
__EOF__
}
@@ -178,7 +178,7 @@
"--debug") BUILD_TYPE="debug" ;;
"--release") BUILD_TYPE="release" ;;
"--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;;
- "--toolkit") echo "option '$ARG' needs a value:"; echo " $ARG=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|motif)"; abort_configure ;;
+ "--toolkit") echo "option '$ARG' needs a value:"; echo " $ARG=(libadwaita|gtk4|gtk3|cocoa|qt5|motif)"; abort_configure ;;
"-"*) echo "unknown option: $ARG"; abort_configure ;;
esac
done
@@ -202,6 +202,22 @@
: ${mandir:='${datarootdir}/man'}
: ${localedir:='${datarootdir}/locale'}
+# remember the above values and compare them later
+orig_bindir="$bindir"
+orig_sbindir="$sbindir"
+orig_libdir="$libdir"
+orig_libexecdir="$libexecdir"
+orig_datarootdir="$datarootdir"
+orig_datadir="$datadir"
+orig_sysconfdir="$sysconfdir"
+orig_sharedstatedir="$sharedstatedir"
+orig_localstatedir="$localstatedir"
+orig_runstatedir="$runstatedir"
+orig_includedir="$includedir"
+orig_infodir="$infodir"
+orig_mandir="$mandir"
+orig_localedir="$localedir"
+
# check if a config.site exists and load it
if [ -n "$CONFIG_SITE" ]; then
# CONFIG_SITE may contain space separated file names
@@ -251,6 +267,9 @@
# check languages
lang_c=
lang_cpp=
+if detect_cpp_compiler ; then
+ lang_cpp=1
+fi
if detect_c_compiler ; then
lang_c=1
fi
@@ -279,32 +298,6 @@
fi
}
-dependency_error_gtk2legacy()
-{
- print_check_msg "$dep_checked_gtk2legacy" "checking for gtk2legacy... "
- # dependency gtk2legacy
- while true
- do
- if [ -z "$PKG_CONFIG" ]; then
- break
- fi
- if test_pkg_config "gtk+-2.0" "" "" "" ; then
- TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-2.0`"
- TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-2.0`"
- else
- break
- fi
- TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK2 -DUI_GTK2LEGACY"
- TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread"
- print_check_msg "$dep_checked_gtk2legacy" "yes\n"
- dep_checked_gtk2legacy=1
- return 1
- done
-
- print_check_msg "$dep_checked_gtk2legacy" "no\n"
- dep_checked_gtk2legacy=1
- return 0
-}
dependency_error_curl()
{
print_check_msg "$dep_checked_curl" "checking for curl... "
@@ -399,6 +392,31 @@
dep_checked_gtk2=1
return 0
}
+dependency_error_sqlite()
+{
+ print_check_msg "$dep_checked_sqlite" "checking for sqlite... "
+ # dependency sqlite
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "sqlite3" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags sqlite3`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs sqlite3`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DDBU_SQLITE"
+ print_check_msg "$dep_checked_sqlite" "yes\n"
+ dep_checked_sqlite=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_sqlite" "no\n"
+ dep_checked_sqlite=1
+ return 0
+}
dependency_error_gtk3()
{
print_check_msg "$dep_checked_gtk3" "checking for gtk3... "
@@ -451,6 +469,277 @@
dep_checked_gtk4=1
return 0
}
+dependency_error_webkitgtk6()
+{
+ print_check_msg "$dep_checked_webkitgtk6" "checking for webkitgtk6... "
+ # dependency webkitgtk6
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "webkitgtk-6.0" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags webkitgtk-6.0`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs webkitgtk-6.0`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WEBVIEW"
+ print_check_msg "$dep_checked_webkitgtk6" "yes\n"
+ dep_checked_webkitgtk6=1
+ return 1
+ done
+
+ # dependency webkitgtk6
+ while true
+ do
+ print_check_msg "$dep_checked_webkitgtk6" "yes\n"
+ dep_checked_webkitgtk6=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_webkitgtk6" "no\n"
+ dep_checked_webkitgtk6=1
+ return 0
+}
+dependency_error_libxml2()
+{
+ print_check_msg "$dep_checked_libxml2" "checking for libxml2... "
+ # dependency libxml2 platform="windows"
+ while true
+ do
+ if notisplatform "windows"; then
+ break
+ fi
+ if tmp_flags=`xml2-config --cflags` ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
+ else
+ break
+ fi
+ if tmp_flags=`xml2-config --libs` ; then
+ TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
+ else
+ break
+ fi
+ print_check_msg "$dep_checked_libxml2" "yes\n"
+ dep_checked_libxml2=1
+ return 1
+ done
+
+ # dependency libxml2 platform="macos"
+ while true
+ do
+ if notisplatform "macos"; then
+ break
+ fi
+ if tmp_flags=`xml2-config --cflags` ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
+ else
+ break
+ fi
+ if tmp_flags=`xml2-config --libs` ; then
+ TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
+ else
+ break
+ fi
+ print_check_msg "$dep_checked_libxml2" "yes\n"
+ dep_checked_libxml2=1
+ return 1
+ done
+
+ # dependency libxml2
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "libxml-2.0" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags libxml-2.0`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs libxml-2.0`"
+ else
+ break
+ fi
+ print_check_msg "$dep_checked_libxml2" "yes\n"
+ dep_checked_libxml2=1
+ return 1
+ done
+
+ # dependency libxml2
+ while true
+ do
+ if tmp_flags=`xml2-config --cflags` ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
+ else
+ break
+ fi
+ if tmp_flags=`xml2-config --libs` ; then
+ TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
+ else
+ break
+ fi
+ print_check_msg "$dep_checked_libxml2" "yes\n"
+ dep_checked_libxml2=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_libxml2" "no\n"
+ dep_checked_libxml2=1
+ return 0
+}
+dependency_error_webkit2gtk4()
+{
+ print_check_msg "$dep_checked_webkit2gtk4" "checking for webkit2gtk4... "
+ # dependency webkit2gtk4
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "webkit2gtk-4.1" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags webkit2gtk-4.1`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs webkit2gtk-4.1`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WEBVIEW"
+ print_check_msg "$dep_checked_webkit2gtk4" "yes\n"
+ dep_checked_webkit2gtk4=1
+ return 1
+ done
+
+ # dependency webkit2gtk4
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "webkit2gtk-4.0" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags webkit2gtk-4.0`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs webkit2gtk-4.0`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WEBVIEW"
+ print_check_msg "$dep_checked_webkit2gtk4" "yes\n"
+ dep_checked_webkit2gtk4=1
+ return 1
+ done
+
+ # dependency webkit2gtk4
+ while true
+ do
+ print_check_msg "$dep_checked_webkit2gtk4" "yes\n"
+ dep_checked_webkit2gtk4=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_webkit2gtk4" "no\n"
+ dep_checked_webkit2gtk4=1
+ return 0
+}
+dependency_error_cocoa()
+{
+ print_check_msg "$dep_checked_cocoa" "checking for cocoa... "
+ # dependency cocoa platform="macos"
+ while true
+ do
+ if notisplatform "macos"; then
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_COCOA"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS -lobjc -framework Cocoa"
+ print_check_msg "$dep_checked_cocoa" "yes\n"
+ dep_checked_cocoa=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_cocoa" "no\n"
+ dep_checked_cocoa=1
+ return 0
+}
+dependency_error_winui()
+{
+ print_check_msg "$dep_checked_winui" "checking for winui... "
+ # dependency winui platform="windows"
+ while true
+ do
+ if notisplatform "windows"; then
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WINUI"
+ print_check_msg "$dep_checked_winui" "yes\n"
+ dep_checked_winui=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_winui" "no\n"
+ dep_checked_winui=1
+ return 0
+}
+dependency_error_gtk2legacy()
+{
+ print_check_msg "$dep_checked_gtk2legacy" "checking for gtk2legacy... "
+ # dependency gtk2legacy
+ while true
+ do
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if test_pkg_config "gtk+-2.0" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags gtk+-2.0`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs gtk+-2.0`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_GTK2 -DUI_GTK2LEGACY"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS -lpthread"
+ print_check_msg "$dep_checked_gtk2legacy" "yes\n"
+ dep_checked_gtk2legacy=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_gtk2legacy" "no\n"
+ dep_checked_gtk2legacy=1
+ return 0
+}
+dependency_error_qt5()
+{
+ print_check_msg "$dep_checked_qt5" "checking for qt5... "
+ # dependency qt5
+ while true
+ do
+ if [ -z "$lang_cpp" ] ; then
+ break
+ fi
+ if [ -z "$PKG_CONFIG" ]; then
+ break
+ fi
+ if which qmake-qt5 > /dev/null ; then
+ :
+ else
+ break
+ fi
+ if test_pkg_config "Qt5Widgets" "" "" "" ; then
+ TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags Qt5Widgets`"
+ TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs Qt5Widgets`"
+ else
+ break
+ fi
+ TEMP_CFLAGS="$TEMP_CFLAGS -DUI_QT5"
+ cat >> $TEMP_DIR/make.mk << __EOF__
+# Dependency: qt5
+QMAKE = qmake-qt5
+QT_PRO_FILE = qt5.pro
+__EOF__
+ print_check_msg "$dep_checked_qt5" "yes\n"
+ dep_checked_qt5=1
+ return 1
+ done
+
+ print_check_msg "$dep_checked_qt5" "no\n"
+ dep_checked_qt5=1
+ return 0
+}
dependency_error_openssl()
{
print_check_msg "$dep_checked_openssl" "checking for openssl... "
@@ -570,129 +859,6 @@
dep_checked_motif=1
return 0
}
-dependency_error_libxml2()
-{
- print_check_msg "$dep_checked_libxml2" "checking for libxml2... "
- # dependency libxml2 platform="windows"
- while true
- do
- if notisplatform "windows"; then
- break
- fi
- if tmp_flags=`xml2-config --cflags` ; then
- TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
- else
- break
- fi
- if tmp_flags=`xml2-config --libs` ; then
- TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
- else
- break
- fi
- print_check_msg "$dep_checked_libxml2" "yes\n"
- dep_checked_libxml2=1
- return 1
- done
-
- # dependency libxml2 platform="macos"
- while true
- do
- if notisplatform "macos"; then
- break
- fi
- if tmp_flags=`xml2-config --cflags` ; then
- TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
- else
- break
- fi
- if tmp_flags=`xml2-config --libs` ; then
- TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
- else
- break
- fi
- print_check_msg "$dep_checked_libxml2" "yes\n"
- dep_checked_libxml2=1
- return 1
- done
-
- # dependency libxml2
- while true
- do
- if [ -z "$PKG_CONFIG" ]; then
- break
- fi
- if test_pkg_config "libxml-2.0" "" "" "" ; then
- TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags libxml-2.0`"
- TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs libxml-2.0`"
- else
- break
- fi
- print_check_msg "$dep_checked_libxml2" "yes\n"
- dep_checked_libxml2=1
- return 1
- done
-
- # dependency libxml2
- while true
- do
- if tmp_flags=`xml2-config --cflags` ; then
- TEMP_CFLAGS="$TEMP_CFLAGS $tmp_flags"
- else
- break
- fi
- if tmp_flags=`xml2-config --libs` ; then
- TEMP_LDFLAGS="$TEMP_LDFLAGS $tmp_flags"
- else
- break
- fi
- print_check_msg "$dep_checked_libxml2" "yes\n"
- dep_checked_libxml2=1
- return 1
- done
-
- print_check_msg "$dep_checked_libxml2" "no\n"
- dep_checked_libxml2=1
- return 0
-}
-dependency_error_cocoa()
-{
- print_check_msg "$dep_checked_cocoa" "checking for cocoa... "
- # dependency cocoa platform="macos"
- while true
- do
- if notisplatform "macos"; then
- break
- fi
- TEMP_CFLAGS="$TEMP_CFLAGS -DUI_COCOA"
- TEMP_LDFLAGS="$TEMP_LDFLAGS -lobjc -framework Cocoa"
- print_check_msg "$dep_checked_cocoa" "yes\n"
- dep_checked_cocoa=1
- return 1
- done
-
- print_check_msg "$dep_checked_cocoa" "no\n"
- dep_checked_cocoa=1
- return 0
-}
-dependency_error_winui()
-{
- print_check_msg "$dep_checked_winui" "checking for winui... "
- # dependency winui platform="windows"
- while true
- do
- if notisplatform "windows"; then
- break
- fi
- TEMP_CFLAGS="$TEMP_CFLAGS -DUI_WINUI"
- print_check_msg "$dep_checked_winui" "yes\n"
- dep_checked_winui=1
- return 1
- done
-
- print_check_msg "$dep_checked_winui" "no\n"
- dep_checked_winui=1
- return 0
-}
# start collecting dependency information
echo > "$TEMP_DIR/flags.mk"
@@ -712,6 +878,9 @@
break
fi
+ cat >> "$TEMP_DIR/make.mk" << __EOF__
+LD = \$(CC)
+__EOF__
break
done
break
@@ -727,6 +896,7 @@
cat >> "$TEMP_DIR/make.mk" << __EOF__
OBJ_EXT = .o
LIB_EXT = .a
+SHLIB_EXT = .dylib
LIB_PREFIX = lib
PACKAGE_SCRIPT = package_osx.sh
__EOF__
@@ -748,6 +918,7 @@
cat >> "$TEMP_DIR/make.mk" << __EOF__
OBJ_EXT = .o
LIB_EXT = .a
+SHLIB_EXT = .so
LIB_PREFIX = lib
PACKAGE_SCRIPT = package_unix.sh
__EOF__
@@ -757,6 +928,19 @@
done
while true
do
+ while true
+ do
+
+ cat >> "$TEMP_DIR/make.mk" << __EOF__
+BUILD_BIN_DIR = bin
+BUILD_LIB_DIR = lib
+__EOF__
+ break
+ done
+ break
+done
+while true
+do
if notisplatform "bsd"; then
break
fi
@@ -770,6 +954,16 @@
break
done
+# build type
+if [ "$BUILD_TYPE" = "debug" ]; then
+ TEMP_CFLAGS="\${DEBUG_CC_FLAGS} $TEMP_CFLAGS"
+ TEMP_CXXFLAGS="\${DEBUG_CXX_FLAGS} $TEMP_CXXFLAGS"
+fi
+if [ "$BUILD_TYPE" = "release" ]; then
+ TEMP_CFLAGS="\${RELEASE_CC_FLAGS} $TEMP_CFLAGS"
+ TEMP_CXXFLAGS="\${RELEASE_CXX_FLAGS} $TEMP_CXXFLAGS"
+fi
+
# add general dependency flags to flags.mk
echo "# general flags" >> "$TEMP_DIR/flags.mk"
if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then
@@ -791,12 +985,17 @@
if dependency_error_libadwaita ; then
VERR=1
fi
+ if dependency_error_webkitgtk6 ; then
+ VERR=1
+ fi
if [ $VERR -ne 0 ]; then
return 1
fi
cat >> "$TEMP_DIR/make.mk" << __EOF__
TOOLKIT = gtk
GTKOBJ = draw_cairo.o
+APP_PLATFORM_SRC = gtk-text.c
+APP_PLATFORM_SRC += gtk-image.c
__EOF__
return 0
}
@@ -806,12 +1005,17 @@
if dependency_error_gtk4 ; then
VERR=1
fi
+ if dependency_error_webkitgtk6 ; then
+ VERR=1
+ fi
if [ $VERR -ne 0 ]; then
return 1
fi
cat >> "$TEMP_DIR/make.mk" << __EOF__
TOOLKIT = gtk
GTKOBJ = draw_cairo.o
+APP_PLATFORM_SRC = gtk-text.c
+APP_PLATFORM_SRC += gtk-image.c
__EOF__
return 0
}
@@ -821,19 +1025,7 @@
if dependency_error_gtk3 ; then
VERR=1
fi
- if [ $VERR -ne 0 ]; then
- return 1
- fi
- cat >> "$TEMP_DIR/make.mk" << __EOF__
-TOOLKIT = gtk
-GTKOBJ = draw_cairo.o
-__EOF__
- return 0
-}
-checkopt_toolkit_gtk2()
-{
- VERR=0
- if dependency_error_gtk2 ; then
+ if dependency_error_webkit2gtk4 ; then
VERR=1
fi
if [ $VERR -ne 0 ]; then
@@ -842,21 +1034,24 @@
cat >> "$TEMP_DIR/make.mk" << __EOF__
TOOLKIT = gtk
GTKOBJ = draw_cairo.o
+GTKOBJ = draw_cairo.o
+APP_PLATFORM_SRC = gtk-text.c
+APP_PLATFORM_SRC += gtk-image.c
__EOF__
return 0
}
-checkopt_toolkit_gtk2legacy()
+checkopt_toolkit_cocoa()
{
VERR=0
- if dependency_error_gtk2legacy ; then
+ if dependency_error_cocoa ; then
VERR=1
fi
if [ $VERR -ne 0 ]; then
return 1
fi
cat >> "$TEMP_DIR/make.mk" << __EOF__
-TOOLKIT = gtk
-GTKOBJ = draw_gdk.o
+TOOLKIT = cocoa
+APP_PLATFORM_SRC = cocoa-text.m
__EOF__
return 0
}
@@ -871,22 +1066,7 @@
fi
cat >> "$TEMP_DIR/make.mk" << __EOF__
TOOLKIT = qt
-LD = $(CXX)
-__EOF__
- return 0
-}
-checkopt_toolkit_qt4()
-{
- VERR=0
- if dependency_error_qt4 ; then
- VERR=1
- fi
- if [ $VERR -ne 0 ]; then
- return 1
- fi
- cat >> "$TEMP_DIR/make.mk" << __EOF__
-TOOLKIT = qt
-LD = $(CXX)
+LD = \$(CXX)
__EOF__
return 0
}
@@ -938,24 +1118,33 @@
if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
echo "DAV_CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
fi
-if [ "$BUILD_TYPE" = "debug" ]; then
- if [ -n "$lang_c" ]; then
- echo 'DAV_CFLAGS += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo 'DAV_CXXFLAGS += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
+if [ -n "${TEMP_LDFLAGS}" ]; then
+ echo "DAV_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk"
fi
-if [ "$BUILD_TYPE" = "release" ]; then
- if [ -n "$lang_c" ]; then
- echo 'DAV_CFLAGS += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo 'DAV_CXXFLAGS += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
+
+echo >> "$TEMP_DIR/flags.mk"
+echo "configuring target: dbu"
+echo "# flags for target dbu" >> "$TEMP_DIR/flags.mk"
+TEMP_CFLAGS=
+TEMP_CXXFLAGS=
+TEMP_LDFLAGS=
+
+if dependency_error_sqlite; then
+ DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED sqlite "
+ ERROR=1
+fi
+
+# Features
+
+
+if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then
+ echo "DBU_CFLAGS += $TEMP_CFLAGS" >> "$TEMP_DIR/flags.mk"
+fi
+if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
+ echo "DBU_CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
fi
if [ -n "${TEMP_LDFLAGS}" ]; then
- echo "DAV_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk"
+ echo "DBU_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk"
fi
echo >> "$TEMP_DIR/flags.mk"
@@ -990,6 +1179,11 @@
break
fi
fi
+ if checkopt_toolkit_libadwaita ; then
+ echo " toolkit: libadwaita" >> "$TEMP_DIR/options"
+ ERROR=0
+ break
+ fi
if checkopt_toolkit_gtk4 ; then
echo " toolkit: gtk4" >> "$TEMP_DIR/options"
ERROR=0
@@ -1000,21 +1194,6 @@
ERROR=0
break
fi
- if checkopt_toolkit_qt5 ; then
- echo " toolkit: qt5" >> "$TEMP_DIR/options"
- ERROR=0
- break
- fi
- if checkopt_toolkit_gtk2 ; then
- echo " toolkit: gtk2" >> "$TEMP_DIR/options"
- ERROR=0
- break
- fi
- if checkopt_toolkit_qt4 ; then
- echo " toolkit: qt4" >> "$TEMP_DIR/options"
- ERROR=0
- break
- fi
if checkopt_toolkit_motif ; then
echo " toolkit: motif" >> "$TEMP_DIR/options"
ERROR=0
@@ -1056,17 +1235,9 @@
ERROR=1
DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
fi
- elif [ "$OPT_TOOLKIT" = "gtk2" ]; then
+ elif [ "$OPT_TOOLKIT" = "cocoa" ]; then
echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options
- if checkopt_toolkit_gtk2 ; then
- :
- else
- ERROR=1
- DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
- fi
- elif [ "$OPT_TOOLKIT" = "gtk2legacy" ]; then
- echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options
- if checkopt_toolkit_gtk2legacy ; then
+ if checkopt_toolkit_cocoa ; then
:
else
ERROR=1
@@ -1080,14 +1251,6 @@
ERROR=1
DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
fi
- elif [ "$OPT_TOOLKIT" = "qt4" ]; then
- echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options
- if checkopt_toolkit_qt4 ; then
- :
- else
- ERROR=1
- DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
- fi
elif [ "$OPT_TOOLKIT" = "motif" ]; then
echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options
if checkopt_toolkit_motif ; then
@@ -1099,7 +1262,7 @@
else
echo
echo "Invalid option value - usage:"
- echo " --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|motif)"
+ echo " --toolkit=(libadwaita|gtk4|gtk3|cocoa|qt5|motif)"
abort_configure
fi
fi
@@ -1110,22 +1273,6 @@
if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
echo "TK_CXXFLAGS += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
fi
-if [ "$BUILD_TYPE" = "debug" ]; then
- if [ -n "$lang_c" ]; then
- echo 'TK_CFLAGS += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo 'TK_CXXFLAGS += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
-fi
-if [ "$BUILD_TYPE" = "release" ]; then
- if [ -n "$lang_c" ]; then
- echo 'TK_CFLAGS += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo 'TK_CXXFLAGS += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
-fi
if [ -n "${TEMP_LDFLAGS}" ]; then
echo "TK_LDFLAGS += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk"
fi
@@ -1141,20 +1288,81 @@
echo "configure finished"
echo
+echo "Toolchain"
+echo " name: $TOOLCHAIN_NAME"
+if [ -n "$TOOLCHAIN_CC" ]; then
+ echo " cc: $TOOLCHAIN_CC"
+fi
+if [ -n "$TOOLCHAIN_CXX" ]; then
+ echo " cxx: $TOOLCHAIN_CXX"
+fi
+if [ -n "$TOOLCHAIN_WSIZE" ]; then
+ echo " word size: $TOOLCHAIN_WSIZE bit"
+fi
+if [ -n "$TOOLCHAIN_CSTD" ]; then
+ echo " default C std: $TOOLCHAIN_CSTD"
+fi
+echo
echo "Build Config:"
-echo " PREFIX: $prefix"
-echo " TOOLCHAIN: $TOOLCHAIN_NAME"
+echo " prefix: $prefix"
+echo " exec_prefix: $exec_prefix"
+if [ "$orig_bindir" != "$bindir" ]; then
+ echo " bindir: $bindir"
+fi
+if [ "$orig_sbindir" != "$sbindir" ]; then
+ echo " sbindir: $sbindir"
+fi
+if [ "$orig_libdir" != "$libdir" ]; then
+ echo " libdir: $libdir"
+fi
+if [ "$orig_libexecdir" != "$libexecdir" ]; then
+ echo " libexecdir: $libexecdir"
+fi
+if [ "$orig_datarootdir" != "$datarootdir" ]; then
+ echo " datarootdir: $datarootdir"
+fi
+if [ "$orig_datadir" != "$datadir" ]; then
+ echo " datadir: $datadir"
+fi
+if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
+ echo " sysconfdir: $sysconfdir"
+fi
+if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
+ echo " sharedstatedir: $sharedstatedir"
+fi
+if [ "$orig_localstatedir" != "$localstatedir" ]; then
+ echo " localstatedir: $localstatedir"
+fi
+if [ "$orig_runstatedir" != "$runstatedir" ]; then
+ echo " runstatedir: $runstatedir"
+fi
+if [ "$orig_includedir" != "$includedir" ]; then
+ echo " includedir: $includedir"
+fi
+if [ "$orig_infodir" != "$infodir" ]; then
+ echo " infodir: $infodir"
+fi
+if [ "$orig_mandir" != "$mandir" ]; then
+ echo " mandir: $mandir"
+fi
+if [ "$orig_localedir" != "$localedir" ]; then
+ echo " localedir: $localedir"
+fi
+echo
echo "Options:"
cat "$TEMP_DIR/options"
echo
# generate the config.mk file
+pwd=`pwd`
cat > "$TEMP_DIR/config.mk" << __EOF__
#
-# config.mk generated by configure
+# config.mk generated by:
+# pwd: $pwd
+# $0 $@
#
__EOF__
write_toolchain_defaults "$TEMP_DIR/toolchain.mk"
-cat "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
+cat "$TEMP_DIR/config.mk" "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
rm -Rf "$TEMP_DIR"
diff -r b34bd1557c6c -r 77254bd6dccb libidav/config.c
--- a/libidav/config.c Sat Apr 05 17:57:04 2025 +0200
+++ b/libidav/config.c Sun Jul 20 22:04:39 2025 +0200
@@ -198,7 +198,7 @@
DavConfig* dav_config_new(xmlDoc *doc) {
- CxMempool *cfg_mp = cxMempoolCreate(128, NULL);
+ CxMempool *cfg_mp = cxMempoolCreateSimple(128);
DavConfig *config = cxMalloc(cfg_mp->allocator, sizeof(DavConfig));
memset(config, 0, sizeof(DavConfig));
config->mp = cfg_mp;
diff -r b34bd1557c6c -r 77254bd6dccb libidav/resource.c
--- a/libidav/resource.c Sat Apr 05 17:57:04 2025 +0200
+++ b/libidav/resource.c Sun Jul 20 22:04:39 2025 +0200
@@ -786,7 +786,7 @@
}
int dav_load_prop(DavResource *res, DavPropName *properties, size_t numprop) {
- CxMempool *mp = cxMempoolCreate(64, NULL);
+ CxMempool *mp = cxMempoolCreateSimple(64);
const CxAllocator *a = mp->allocator;
CxList *proplist = cxArrayListCreate(a, NULL, sizeof(DavProperty), numprop);
diff -r b34bd1557c6c -r 77254bd6dccb make/configure.vm
--- a/make/configure.vm Sat Apr 05 17:57:04 2025 +0200
+++ b/make/configure.vm Sun Jul 20 22:04:39 2025 +0200
@@ -108,8 +108,8 @@
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
Build Types:
---debug add extra compile flags for debug builds
---release add extra compile flags for release builds
+ --debug add extra compile flags for debug builds
+ --release add extra compile flags for release builds
#if( $options.size() > 0 )
Options:
@@ -244,6 +244,22 @@
: ${mandir:='${datarootdir}/man'}
: ${localedir:='${datarootdir}/locale'}
+# remember the above values and compare them later
+orig_bindir="$bindir"
+orig_sbindir="$sbindir"
+orig_libdir="$libdir"
+orig_libexecdir="$libexecdir"
+orig_datarootdir="$datarootdir"
+orig_datadir="$datadir"
+orig_sysconfdir="$sysconfdir"
+orig_sharedstatedir="$sharedstatedir"
+orig_localstatedir="$localstatedir"
+orig_runstatedir="$runstatedir"
+orig_includedir="$includedir"
+orig_infodir="$infodir"
+orig_mandir="$mandir"
+orig_localedir="$localedir"
+
# check if a config.site exists and load it
if [ -n "$CONFIG_SITE" ]; then
# CONFIG_SITE may contain space separated file names
@@ -485,6 +501,16 @@
done
#end
+# build type
+if [ "$BUILD_TYPE" = "debug" ]; then
+ TEMP_CFLAGS="\${DEBUG_CC_FLAGS} $TEMP_CFLAGS"
+ TEMP_CXXFLAGS="\${DEBUG_CXX_FLAGS} $TEMP_CXXFLAGS"
+fi
+if [ "$BUILD_TYPE" = "release" ]; then
+ TEMP_CFLAGS="\${RELEASE_CC_FLAGS} $TEMP_CFLAGS"
+ TEMP_CXXFLAGS="\${RELEASE_CXX_FLAGS} $TEMP_CXXFLAGS"
+fi
+
# add general dependency flags to flags.mk
echo "# general flags" >> "$TEMP_DIR/flags.mk"
if [ -n "${TEMP_CFLAGS}" ] && [ -n "$lang_c" ]; then
@@ -661,22 +687,6 @@
if [ -n "${TEMP_CXXFLAGS}" ] && [ -n "$lang_cpp" ]; then
echo "${target.cxxFlags} += $TEMP_CXXFLAGS" >> "$TEMP_DIR/flags.mk"
fi
-if [ "$BUILD_TYPE" = "debug" ]; then
- if [ -n "$lang_c" ]; then
- echo '${target.cFlags} += ${DEBUG_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo '${target.cxxFlags} += ${DEBUG_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
-fi
-if [ "$BUILD_TYPE" = "release" ]; then
- if [ -n "$lang_c" ]; then
- echo '${target.cFlags} += ${RELEASE_CC_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
- if [ -n "$lang_cpp" ]; then
- echo '${target.cxxFlags} += ${RELEASE_CXX_FLAGS}' >> "$TEMP_DIR/flags.mk"
- fi
-fi
if [ -n "${TEMP_LDFLAGS}" ]; then
echo "${target.ldFlags} += $TEMP_LDFLAGS" >> "$TEMP_DIR/flags.mk"
fi
@@ -693,14 +703,73 @@
echo "configure finished"
echo
+echo "Toolchain"
+echo " name: $TOOLCHAIN_NAME"
+if [ -n "$TOOLCHAIN_CC" ]; then
+ echo " cc: $TOOLCHAIN_CC"
+fi
+if [ -n "$TOOLCHAIN_CXX" ]; then
+ echo " cxx: $TOOLCHAIN_CXX"
+fi
+if [ -n "$TOOLCHAIN_WSIZE" ]; then
+ echo " word size: $TOOLCHAIN_WSIZE bit"
+fi
+if [ -n "$TOOLCHAIN_CSTD" ]; then
+ echo " default C std: $TOOLCHAIN_CSTD"
+fi
+echo
echo "Build Config:"
-echo " PREFIX: $prefix"
-echo " TOOLCHAIN: $TOOLCHAIN_NAME"
+echo " prefix: $prefix"
+echo " exec_prefix: $exec_prefix"
+if [ "$orig_bindir" != "$bindir" ]; then
+ echo " bindir: $bindir"
+fi
+if [ "$orig_sbindir" != "$sbindir" ]; then
+ echo " sbindir: $sbindir"
+fi
+if [ "$orig_libdir" != "$libdir" ]; then
+ echo " libdir: $libdir"
+fi
+if [ "$orig_libexecdir" != "$libexecdir" ]; then
+ echo " libexecdir: $libexecdir"
+fi
+if [ "$orig_datarootdir" != "$datarootdir" ]; then
+ echo " datarootdir: $datarootdir"
+fi
+if [ "$orig_datadir" != "$datadir" ]; then
+ echo " datadir: $datadir"
+fi
+if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
+ echo " sysconfdir: $sysconfdir"
+fi
+if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
+ echo " sharedstatedir: $sharedstatedir"
+fi
+if [ "$orig_localstatedir" != "$localstatedir" ]; then
+ echo " localstatedir: $localstatedir"
+fi
+if [ "$orig_runstatedir" != "$runstatedir" ]; then
+ echo " runstatedir: $runstatedir"
+fi
+if [ "$orig_includedir" != "$includedir" ]; then
+ echo " includedir: $includedir"
+fi
+if [ "$orig_infodir" != "$infodir" ]; then
+ echo " infodir: $infodir"
+fi
+if [ "$orig_mandir" != "$mandir" ]; then
+ echo " mandir: $mandir"
+fi
+if [ "$orig_localedir" != "$localedir" ]; then
+ echo " localedir: $localedir"
+fi
#if ( $options.size() > 0 )
+echo
echo "Options:"
cat "$TEMP_DIR/options"
#end
#if ( $features.size() > 0 )
+echo
echo "Features:"
#foreach( $feature in $features )
if [ -n "${D}${feature.varName}" ]; then
@@ -713,12 +782,15 @@
echo
# generate the config.mk file
+pwd=`pwd`
cat > "$TEMP_DIR/config.mk" << __EOF__
#
-# config.mk generated by configure
+# config.mk generated by:
+# pwd: $pwd
+# $0 $@
#
__EOF__
write_toolchain_defaults "$TEMP_DIR/toolchain.mk"
-cat "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
+cat "$TEMP_DIR/config.mk" "$TEMP_DIR/vars.mk" "$TEMP_DIR/toolchain.mk" "$TEMP_DIR/flags.mk" "$TEMP_DIR/make.mk" > config.mk
rm -Rf "$TEMP_DIR"
diff -r b34bd1557c6c -r 77254bd6dccb make/project.xml
--- a/make/project.xml Sat Apr 05 17:57:04 2025 +0200
+++ b/make/project.xml Sun Jul 20 22:04:39 2025 +0200
@@ -2,6 +2,7 @@
c
+ LD = \$(CC)
@@ -16,6 +17,11 @@
curl-config --libs
+
+ sqlite3
+ -DDBU_SQLITE
+
+
xml2-config --cflags
xml2-config --libs
@@ -75,21 +81,34 @@
-DUI_WINUI
-
+
+
+ webkit2gtk-4.1
+ -DUI_WEBVIEW
+
+
+ webkit2gtk-4.0
+ -DUI_WEBVIEW
+
+
+
which qmake-qt5
- qmake-qt5 -o - /dev/null | grep DEFINES\
- qmake-qt5 -o - /dev/null | grep INCPATH\
- qmake-qt5 -o - /dev/null | grep LIBS\
+ cpp
+ -DUI_QT5
+ Qt5Widgets
+ QMAKE = qmake-qt5
+ QT_PRO_FILE = qt5.pro
- -->
+
-DUI_COCOA
-lobjc -framework Cocoa
@@ -108,15 +127,21 @@
OBJ_EXT = .o
LIB_EXT = .a
+ SHLIB_EXT = .dylib
LIB_PREFIX = lib
PACKAGE_SCRIPT = package_osx.sh
OBJ_EXT = .o
LIB_EXT = .a
+ SHLIB_EXT = .so
LIB_PREFIX = lib
PACKAGE_SCRIPT = package_unix.sh
+
+ BUILD_BIN_DIR = bin
+ BUILD_LIB_DIR = lib
+
-I/usr/local/include
@@ -127,42 +152,43 @@
curl,libxml2,openssl
+
+ sqlite
+
+
diff -r b34bd1557c6c -r 77254bd6dccb make/toolchain.sh
--- a/make/toolchain.sh Sat Apr 05 17:57:04 2025 +0200
+++ b/make/toolchain.sh Sun Jul 20 22:04:39 2025 +0200
@@ -17,20 +17,28 @@
check_c_compiler()
{
+ command -v $1 2>&1 >/dev/null
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
cat > "$TEMP_DIR/test.c" << __EOF__
/* test file */
#include
int main(int argc, char **argv) {
#if defined(_MSC_VER)
- printf("msc\n");
+ printf("toolchain:msc\n");
#elif defined(__clang__)
- printf("clang gnuc\n");
+ printf("toolchain:clang gnuc\n");
#elif defined(__GNUC__)
- printf("gcc gnuc\n");
+ printf("toolchain:gcc gnuc\n");
#elif defined(__sun)
- printf("suncc\n");
+ printf("toolchain:suncc\n");
#else
- printf("unknown\n");
+ printf("toolchain:unknown\n");
+#endif
+ printf("wsize:%d\n", (int)sizeof(void*)*8);
+#ifdef __STDC_VERSION__
+ printf("stdcversion:%d\n", __STDC_VERSION__);
#endif
return 0;
}
@@ -41,21 +49,26 @@
check_cpp_compiler()
{
+ command -v $1 2>&1 >/dev/null
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
cat > "$TEMP_DIR/test.cpp" << __EOF__
/* test file */
#include
int main(int argc, char **argv) {
#if defined(_MSC_VER)
- std::cout << "msc" << std::endl;
+ std::cout << "toolchain:msc" << std::endl;
#elif defined(__clang__)
- std::cout << "clang gnuc" << std::endl;
+ std::cout << "toolchain:clang gnuc" << std::endl;
#elif defined(__GNUC__)
- std::cout << "gcc gnuc" << std::endl;
+ std::cout << "toolchain:gcc gnuc" << std::endl;
#elif defined(__sun)
- std::cout << "suncc" << std::endl;
+ std::cout << "toolchain:suncc" << std::endl;
#else
- std::cout << "cc" << std::endl;
+ std::cout << "toolchain:unknown" << std::endl;
#endif
+ std::cout << "wsize:" << sizeof(void*)*8 << std::endl;
return 0;
}
__EOF__
@@ -113,6 +126,14 @@
fi
}
+parse_toolchain_properties()
+{
+ info_file="$1"
+ TOOLCHAIN=`grep '^toolchain:' "$info_file" | tail -c +11`
+ TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+ TOOLCHAIN_WSIZE=`grep '^wsize:' "$info_file" | tail -c +7`
+}
+
detect_c_compiler()
{
if [ -n "$TOOLCHAIN_CC" ]; then
@@ -122,8 +143,9 @@
if [ -n "$CC" ]; then
if check_c_compiler "$CC"; then
TOOLCHAIN_CC=$CC
- TOOLCHAIN=`"$TEMP_DIR/checkcc"`
- TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+ "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+ parse_toolchain_properties "$TEMP_DIR/checkcc_out"
+ TOOLCHAIN_CSTD=`grep '^stdcversion:' "$TEMP_DIR/checkcc_out" | tail -c +13`
echo "$CC"
return 0
else
@@ -135,8 +157,9 @@
do
if check_c_compiler "$COMP"; then
TOOLCHAIN_CC=$COMP
- TOOLCHAIN=`"$TEMP_DIR/checkcc"`
- TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+ "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+ parse_toolchain_properties "$TEMP_DIR/checkcc_out"
+ TOOLCHAIN_CSTD=`grep '^stdcversion:' "$TEMP_DIR/checkcc_out" | tail -c +13`
echo "$COMP"
return 0
fi
@@ -156,8 +179,8 @@
if [ -n "$CXX" ]; then
if check_cpp_compiler "$CXX"; then
TOOLCHAIN_CXX=$CXX
- TOOLCHAIN=`"$TEMP_DIR/checkcc"`
- TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+ "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+ parse_toolchain_properties "$TEMP_DIR/checkcc_out"
echo "$CXX"
return 0
else
@@ -169,8 +192,8 @@
do
if check_cpp_compiler "$COMP"; then
TOOLCHAIN_CXX=$COMP
- TOOLCHAIN=`"$TEMP_DIR/checkcc"`
- TOOLCHAIN_NAME=`echo "$TOOLCHAIN" | cut -f1 -d' ' -`
+ "$TEMP_DIR/checkcc" > "$TEMP_DIR/checkcc_out"
+ parse_toolchain_properties "$TEMP_DIR/checkcc_out"
echo "$COMP"
return 0
fi
diff -r b34bd1557c6c -r 77254bd6dccb ucx/Makefile
--- a/ucx/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -49,16 +49,20 @@
OBJ = $(SRC:%.c=../build/ucx/%$(OBJ_EXT))
-UCX_LIB = ../build/lib/libucx$(LIB_EXT)
+UCX_LIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(LIB_EXT)
+UCX_SHLIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(SHLIB_EXT)
-all: ../build/ucx $(UCX_LIB)
+all: $(UCX_LIB) $(UCX_SHLIB)
$(UCX_LIB): $(OBJ)
- $(AR) $(ARFLAGS) $(UCX_LIB) $(OBJ)
+ $(AR) $(ARFLAGS) $@ $(OBJ)
+
+$(UCX_SHLIB): $(OBJ)
+ $(CC) -o $@ $(LDFLAGS) $(SHLIB_LDFLAGS) $(OBJ)
../build/ucx:
mkdir -p ../build/ucx
../build/ucx/%$(OBJ_EXT): %.c
- $(CC) $(CFLAGS) -o $@ -c $<
+ $(CC) $(CFLAGS) $(SHLIB_CFLAGS) -o $@ -c $<
diff -r b34bd1557c6c -r 77254bd6dccb ucx/allocator.c
--- a/ucx/allocator.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/allocator.c Sun Jul 20 22:04:39 2025 +0200
@@ -29,6 +29,7 @@
#include "cx/allocator.h"
#include
+#include
static void *cx_malloc_stdlib(
cx_attr_unused void *d,
@@ -60,18 +61,19 @@
free(mem);
}
-static cx_allocator_class cx_default_allocator_class = {
+static cx_allocator_class cx_stdlib_allocator_class = {
cx_malloc_stdlib,
cx_realloc_stdlib,
cx_calloc_stdlib,
cx_free_stdlib
};
-struct cx_allocator_s cx_default_allocator = {
- &cx_default_allocator_class,
+struct cx_allocator_s cx_stdlib_allocator = {
+ &cx_stdlib_allocator_class,
NULL
};
-const CxAllocator * const cxDefaultAllocator = &cx_default_allocator;
+const CxAllocator * const cxStdlibAllocator = &cx_stdlib_allocator;
+const CxAllocator * cxDefaultAllocator = cxStdlibAllocator;
int cx_reallocate_(
void **mem,
@@ -115,6 +117,17 @@
return allocator->cl->malloc(allocator->data, n);
}
+void *cxZalloc(
+ const CxAllocator *allocator,
+ size_t n
+) {
+ void *mem = allocator->cl->malloc(allocator->data, n);
+ if (mem != NULL) {
+ memset(mem, 0, n);
+ }
+ return mem;
+}
+
void *cxRealloc(
const CxAllocator *allocator,
void *mem,
diff -r b34bd1557c6c -r 77254bd6dccb ucx/array_list.c
--- a/ucx/array_list.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/array_list.c Sun Jul 20 22:04:39 2025 +0200
@@ -36,16 +36,17 @@
static void *cx_array_default_realloc(
void *array,
- size_t capacity,
+ cx_attr_unused size_t old_capacity,
+ size_t new_capacity,
size_t elem_size,
cx_attr_unused CxArrayReallocator *alloc
) {
size_t n;
- if (cx_szmul(capacity, elem_size, &n)) {
+ if (cx_szmul(new_capacity, elem_size, &n)) {
errno = EOVERFLOW;
return NULL;
}
- return realloc(array, n);
+ return cxReallocDefault(array, n);
}
CxArrayReallocator cx_array_default_reallocator_impl = {
@@ -58,13 +59,14 @@
static void *cx_array_advanced_realloc(
void *array,
- size_t capacity,
+ size_t old_capacity,
+ size_t new_capacity,
size_t elem_size,
cx_attr_unused CxArrayReallocator *alloc
) {
// check for overflow
size_t n;
- if (cx_szmul(capacity, elem_size, &n)) {
+ if (cx_szmul(new_capacity, elem_size, &n)) {
errno = EOVERFLOW;
return NULL;
}
@@ -77,7 +79,7 @@
if (array == alloc->ptr2) {
newmem = cxMalloc(al, n);
if (newmem != NULL && array != NULL) {
- memcpy(newmem, array, n);
+ memcpy(newmem, array, old_capacity*elem_size);
}
} else {
newmem = cxRealloc(al, array, n);
@@ -180,7 +182,7 @@
// perform reallocation
void *newmem = reallocator->realloc(
- *array, newcap, elem_size, reallocator
+ *array, oldcap, newcap, elem_size, reallocator
);
if (newmem == NULL) {
return 1; // LCOV_EXCL_LINE
@@ -286,7 +288,7 @@
// perform reallocation
void *newmem = reallocator->realloc(
- *target, newcap, elem_size, reallocator
+ *target, oldcap, newcap, elem_size, reallocator
);
if (newmem == NULL) {
return 1;
@@ -366,13 +368,14 @@
// store some counts
size_t old_size = *size;
+ size_t old_capacity = *capacity;
size_t needed_capacity = old_size + elem_count;
// if we need more than we have, try a reallocation
- if (needed_capacity > *capacity) {
+ if (needed_capacity > old_capacity) {
size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX);
void *new_mem = reallocator->realloc(
- *target, new_capacity, elem_size, reallocator
+ *target, old_capacity, new_capacity, elem_size, reallocator
);
if (new_mem == NULL) {
// give it up right away, there is no contract
@@ -572,7 +575,7 @@
// decide if we can use the local buffer
if (elem_size > CX_ARRAY_SWAP_SBO_SIZE) {
- tmp = malloc(elem_size);
+ tmp = cxMallocDefault(elem_size);
// we don't want to enforce error handling
if (tmp == NULL) abort();
} else {
@@ -591,7 +594,7 @@
// free dynamic memory, if it was needed
if (tmp != sbo_mem) {
- free(tmp);
+ cxFreeDefault(tmp);
}
}
@@ -638,50 +641,38 @@
// get a correctly typed pointer to the list
cx_array_list *arl = (cx_array_list *) list;
- // do we need to move some elements?
- if (index < list->collection.size) {
- const char *first_to_move = (const char *) arl->data;
- first_to_move += index * list->collection.elem_size;
- size_t elems_to_move = list->collection.size - index;
- size_t start_of_moved = index + n;
-
- if (cx_array_copy(
- &arl->data,
- &list->collection.size,
- &arl->capacity,
- 0,
- start_of_moved,
- first_to_move,
- list->collection.elem_size,
- elems_to_move,
- &arl->reallocator
- )) {
- // if moving existing elems is unsuccessful, abort
+ // guarantee enough capacity
+ if (arl->capacity < list->collection.size + n) {
+ size_t new_capacity = list->collection.size + n;
+ new_capacity = new_capacity - (new_capacity % 16) + 16;
+ if (cxReallocateArray(
+ list->collection.allocator,
+ &arl->data, new_capacity,
+ list->collection.elem_size)
+ ) {
return 0;
}
+ arl->capacity = new_capacity;
}
- // note that if we had to move the elements, the following operation
- // is guaranteed to succeed, because we have the memory already allocated
- // therefore, it is impossible to leave this function with an invalid array
+ // determine insert position
+ char *arl_data = arl->data;
+ char *insert_pos = arl_data + index * list->collection.elem_size;
- // place the new elements
- if (cx_array_copy(
- &arl->data,
- &list->collection.size,
- &arl->capacity,
- 0,
- index,
- array,
- list->collection.elem_size,
- n,
- &arl->reallocator
- )) {
- // array list implementation is "all or nothing"
- return 0;
- } else {
- return n;
+ // do we need to move some elements?
+ if (index < list->collection.size) {
+ size_t elems_to_move = list->collection.size - index;
+ char *target = insert_pos + n * list->collection.elem_size;
+ memmove(target, insert_pos, elems_to_move * list->collection.elem_size);
}
+
+ // place the new elements, if any
+ if (array != NULL) {
+ memcpy(insert_pos, array, n * list->collection.elem_size);
+ }
+ list->collection.size += n;
+
+ return n;
}
static size_t cx_arl_insert_sorted(
@@ -709,12 +700,16 @@
}
}
-static int cx_arl_insert_element(
+static void *cx_arl_insert_element(
struct cx_list_s *list,
size_t index,
const void *element
) {
- return 1 != cx_arl_insert_array(list, index, element, 1);
+ if (cx_arl_insert_array(list, index, element, 1) == 1) {
+ return ((char*)((cx_array_list *) list)->data) + index * list->collection.elem_size;
+ } else {
+ return NULL;
+ }
}
static int cx_arl_insert_iter(
@@ -724,26 +719,23 @@
) {
struct cx_list_s *list = iter->src_handle.m;
if (iter->index < list->collection.size) {
- int result = cx_arl_insert_element(
- list,
- iter->index + 1 - prepend,
- elem
- );
- if (result == 0) {
- iter->elem_count++;
- if (prepend != 0) {
- iter->index++;
- iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size;
- }
+ if (cx_arl_insert_element(list,
+ iter->index + 1 - prepend, elem) == NULL) {
+ return 1;
+ }
+ iter->elem_count++;
+ if (prepend != 0) {
+ iter->index++;
+ iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size;
}
- return result;
+ return 0;
} else {
- int result = cx_arl_insert_element(list, list->collection.size, elem);
- if (result == 0) {
- iter->elem_count++;
- iter->index = list->collection.size;
+ if (cx_arl_insert_element(list, list->collection.size, elem) == NULL) {
+ return 1;
}
- return result;
+ iter->elem_count++;
+ iter->index = list->collection.size;
+ return 0;
}
}
diff -r b34bd1557c6c -r 77254bd6dccb ucx/buffer.c
--- a/ucx/buffer.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/buffer.c Sun Jul 20 22:04:39 2025 +0200
@@ -32,6 +32,24 @@
#include
#include
+#ifdef _WIN32
+#include
+#include
+static unsigned long system_page_size() {
+ static unsigned long ps = 0;
+ if (ps == 0) {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ ps = sysinfo.dwPageSize;
+ }
+ return ps;
+}
+#define SYSTEM_PAGE_SIZE system_page_size()
+#else
+#include
+#define SYSTEM_PAGE_SIZE sysconf(_SC_PAGESIZE)
+#endif
+
static int buffer_copy_on_write(CxBuffer* buffer) {
if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0;
void *newspace = cxMalloc(buffer->allocator, buffer->capacity);
@@ -80,7 +98,7 @@
CxBuffer *buffer,
CxBufferFlushConfig config
) {
- buffer->flush = malloc(sizeof(CxBufferFlushConfig));
+ buffer->flush = cxMallocDefault(sizeof(CxBufferFlushConfig));
if (buffer->flush == NULL) return -1; // LCOV_EXCL_LINE
memcpy(buffer->flush, &config, sizeof(CxBufferFlushConfig));
return 0;
@@ -90,7 +108,7 @@
if (buffer->flags & CX_BUFFER_FREE_CONTENTS) {
cxFree(buffer->allocator, buffer->bytes);
}
- free(buffer->flush);
+ cxFreeDefault(buffer->flush);
memset(buffer, 0, sizeof(CxBuffer));
}
@@ -139,6 +157,7 @@
npos = 0;
break;
default:
+ errno = EINVAL;
return -1;
}
@@ -146,11 +165,16 @@
npos += offset;
if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
- errno = EOVERFLOW;
+ // to be compliant with fseek() specification
+ // we return EINVAL on underflow
+ errno = EINVAL;
return -1;
}
if (npos > buffer->size) {
+ // not compliant with fseek() specification
+ // but this is the better behavior for CxBuffer
+ errno = EINVAL;
return -1;
} else {
buffer->pos = npos;
@@ -184,6 +208,28 @@
return 0;
}
+ unsigned long pagesize = SYSTEM_PAGE_SIZE;
+ // if page size is larger than 64 KB - for some reason - truncate to 64 KB
+ if (pagesize > 65536) pagesize = 65536;
+ if (newcap < pagesize) {
+ // when smaller as one page, map to the next power of two
+ newcap--;
+ newcap |= newcap >> 1;
+ newcap |= newcap >> 2;
+ newcap |= newcap >> 4;
+ // last operation only needed for pages larger 4096 bytes
+ // but if/else would be more expensive than just doing this
+ newcap |= newcap >> 8;
+ newcap++;
+ } else {
+ // otherwise, map to a multiple of the page size
+ newcap -= newcap % pagesize;
+ newcap += pagesize;
+ // note: if newcap is already page aligned,
+ // this gives a full additional page (which is good)
+ }
+
+
const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
if (buffer->flags & force_copy_flags) {
void *newspace = cxMalloc(buffer->allocator, newcap);
@@ -203,6 +249,28 @@
}
}
+void cxBufferShrink(
+ CxBuffer *buffer,
+ size_t reserve
+) {
+ // Ensure buffer is in a reallocatable state
+ const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
+ if (buffer->flags & force_copy_flags) {
+ // do nothing when we are not allowed to reallocate
+ return;
+ }
+
+ // calculate new capacity
+ size_t newCapacity = buffer->size + reserve;
+
+ // If new capacity is smaller than current capacity, resize the buffer
+ if (newCapacity < buffer->capacity) {
+ if (0 == cxReallocate(buffer->allocator, &buffer->bytes, newCapacity)) {
+ buffer->capacity = newCapacity;
+ }
+ }
+}
+
static size_t cx_buffer_flush_helper(
const CxBuffer *buffer,
const unsigned char *src,
@@ -399,10 +467,8 @@
}
int cxBufferTerminate(CxBuffer *buffer) {
- bool success = 0 == cxBufferPut(buffer, 0);
- if (success) {
- buffer->pos--;
- buffer->size--;
+ if (0 == cxBufferPut(buffer, 0)) {
+ buffer->size = buffer->pos - 1;
return 0;
} else {
return -1;
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/allocator.h
--- a/ucx/cx/allocator.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/allocator.h Sun Jul 20 22:04:39 2025 +0200
@@ -98,10 +98,17 @@
typedef struct cx_allocator_s CxAllocator;
/**
- * A default allocator using standard library malloc() etc.
+ * A pre-defined allocator using standard library malloc() etc.
*/
cx_attr_export
-extern const CxAllocator * const cxDefaultAllocator;
+extern const CxAllocator * const cxStdlibAllocator;
+
+/**
+ * The default allocator that is used by UCX.
+ * Initialized with cxStdlibAllocator, but you may change it.
+ */
+cx_attr_export
+extern const CxAllocator * cxDefaultAllocator;
/**
* Function pointer type for destructor functions.
@@ -135,6 +142,8 @@
* Reallocate a previously allocated block and changes the pointer in-place,
* if necessary.
*
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
* @par Error handling
* @c errno will be set by realloc() on failure.
*
@@ -158,6 +167,8 @@
*
* The size is calculated by multiplying @p nemb and @p size.
*
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
* @par Error handling
* @c errno will be set by realloc() on failure or when the multiplication of
* @p nmemb and @p size overflows.
@@ -182,6 +193,8 @@
* Reallocate a previously allocated block and changes the pointer in-place,
* if necessary.
*
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
* @par Error handling
* @c errno will be set by realloc() on failure.
*
@@ -199,6 +212,8 @@
*
* The size is calculated by multiplying @p nemb and @p size.
*
+ * @note This will use stdlib reallocate and @em not the cxDefaultAllocator.
+ *
* @par Error handling
* @c errno will be set by realloc() on failure or when the multiplication of
* @p nmemb and @p size overflows.
@@ -213,6 +228,14 @@
cx_reallocatearray_((void**)(mem), nmemb, size)
/**
+ * Allocates memory and sets every byte to zero.
+ *
+ * @param n (@c size_t) the number of bytes
+ * @return (@c void*) a pointer to the allocated memory
+ */
+#define cx_zalloc(n) calloc(1, n)
+
+/**
* Free a block allocated by this allocator.
*
* @note Freeing a block of a different allocator is undefined.
@@ -414,6 +437,57 @@
size_t size
);
+/**
+ * Allocate @p n bytes of memory and sets every byte to zero.
+ *
+ * @param allocator the allocator
+ * @param n the number of bytes
+ * @return a pointer to the allocated memory
+ */
+cx_attr_nodiscard
+cx_attr_nonnull
+cx_attr_malloc
+cx_attr_dealloc_ucx
+cx_attr_allocsize(2)
+cx_attr_export
+void *cxZalloc(
+ const CxAllocator *allocator,
+ size_t n
+);
+
+/**
+ * Convenience macro that invokes cxMalloc() with the cxDefaultAllocator.
+ */
+#define cxMallocDefault(...) cxMalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxZalloc() with the cxDefaultAllocator.
+ */
+#define cxZallocDefault(...) cxZalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxCalloc() with the cxDefaultAllocator.
+ */
+#define cxCallocDefault(...) cxCalloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxRealloc() with the cxDefaultAllocator.
+ */
+#define cxReallocDefault(...) cxRealloc(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocate() with the cxDefaultAllocator.
+ */
+#define cxReallocateDefault(...) cxReallocate(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocateArray() with the cxDefaultAllocator.
+ */
+#define cxReallocateArrayDefault(...) cxReallocateArray(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxReallocArray() with the cxDefaultAllocator.
+ */
+#define cxReallocArrayDefault(...) cxReallocArray(cxDefaultAllocator, __VA_ARGS__)
+/**
+ * Convenience macro that invokes cxFree() with the cxDefaultAllocator.
+ */
+#define cxFreeDefault(...) cxFree(cxDefaultAllocator, __VA_ARGS__)
+
#ifdef __cplusplus
} // extern "C"
#endif
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/array_list.h
--- a/ucx/cx/array_list.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/array_list.h Sun Jul 20 22:04:39 2025 +0200
@@ -123,7 +123,8 @@
* @endcode
*
*
- * The memory for the array is allocated with stdlib malloc().
+ * The memory for the array is allocated with the cxDefaultAllocator.
+ *
* @param array the name of the array
* @param capacity the initial capacity
* @see cx_array_initialize_a()
@@ -133,7 +134,7 @@
#define cx_array_initialize(array, capacity) \
array##_capacity = capacity; \
array##_size = 0; \
- array = malloc(sizeof(array[0]) * capacity)
+ array = cxMallocDefault(sizeof(array[0]) * capacity)
/**
* Initializes an array with the given capacity using the specified allocator.
@@ -149,7 +150,6 @@
* cxFree(al, myarray); // don't forget to free with same allocator
* @endcode
*
- * The memory for the array is allocated with stdlib malloc().
* @param allocator (@c CxAllocator*) the allocator
* @param array the name of the array
* @param capacity the initial capacity
@@ -178,17 +178,19 @@
* or to transport other additional data.
*
* @param array the array to reallocate
- * @param capacity the new capacity (number of elements)
+ * @param old_capacity the old number of elements
+ * @param new_capacity the new number of elements
* @param elem_size the size of each element
* @param alloc a reference to this allocator
* @return a pointer to the reallocated memory or @c NULL on failure
*/
cx_attr_nodiscard
- cx_attr_nonnull_arg(4)
- cx_attr_allocsize(2, 3)
+ cx_attr_nonnull_arg(5)
+ cx_attr_allocsize(3, 4)
void *(*realloc)(
void *array,
- size_t capacity,
+ size_t old_capacity,
+ size_t new_capacity,
size_t elem_size,
struct cx_array_reallocator_s *alloc
);
@@ -217,7 +219,7 @@
typedef struct cx_array_reallocator_s CxArrayReallocator;
/**
- * A default stdlib-based array reallocator.
+ * A default array reallocator that is based on the cxDefaultAllocator.
*/
cx_attr_export
extern CxArrayReallocator *cx_array_default_reallocator;
@@ -225,7 +227,7 @@
/**
* Creates a new array reallocator.
*
- * When @p allocator is @c NULL, the stdlib default allocator will be used.
+ * When @p allocator is @c NULL, the cxDefaultAllocator will be used.
*
* When @p stackmem is not @c NULL, the reallocator is supposed to be used
* @em only for the specific array that is initially located at @p stackmem.
@@ -699,7 +701,7 @@
* to cx_cmp_ptr(), if none is given.
*
* @param allocator the allocator for allocating the list memory
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param comparator the comparator for the elements
* (if @c NULL, and the list is not storing pointers, sort and find
* functions will not work)
@@ -727,7 +729,7 @@
*
* If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
* copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * to cx_cmp_ptr().
*
* @param elem_size (@c size_t) the size of each element in bytes
* @param initial_capacity (@c size_t) the initial number of elements the array can store
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/buffer.h
--- a/ucx/cx/buffer.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/buffer.h Sun Jul 20 22:04:39 2025 +0200
@@ -222,7 +222,7 @@
* @param capacity the capacity of the buffer
* @param allocator the allocator this buffer shall use for automatic
* memory management
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param flags buffer features (see cx_buffer_s.flags)
* @return zero on success, non-zero if a required allocation failed
*/
@@ -305,7 +305,7 @@
* @param capacity the capacity of the buffer
* @param allocator the allocator to use for allocating the structure and the automatic
* memory management within the buffer
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param flags buffer features (see cx_buffer_s.flags)
* @return a pointer to the buffer on success, @c NULL if a required allocation failed
*/
@@ -474,10 +474,14 @@
*
* If the current capacity is not sufficient, the buffer will be extended.
*
+ * The new capacity will be a power of two until the system's page size is reached.
+ * Then, the new capacity will be a multiple of the page size.
+ *
* @param buffer the buffer
* @param capacity the minimum required capacity for this buffer
* @retval zero the capacity was already sufficient or successfully increased
* @retval non-zero on allocation failure
+ * @see cxBufferShrink()
*/
cx_attr_nonnull
cx_attr_export
@@ -487,6 +491,29 @@
);
/**
+ * Shrinks the capacity of the buffer to fit its current size.
+ *
+ * If @p reserve is larger than zero, the buffer is shrunk to its size plus
+ * the number of reserved bytes.
+ *
+ * If the current capacity is not larger than the size plus the reserved bytes,
+ * nothing happens.
+ *
+ * If the #CX_BUFFER_COPY_ON_WRITE or #CX_BUFFER_COPY_ON_EXTEND flag is set,
+ * this function does nothing.
+ *
+ * @param buffer the buffer
+ * @param reserve the number of bytes that shall remain reserved
+ * @see cxBufferMinimumCapacity()
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxBufferShrink(
+ CxBuffer *buffer,
+ size_t reserve
+);
+
+/**
* Writes data to a CxBuffer.
*
* If automatic flushing is not enabled, the data is simply written into the
@@ -674,11 +701,10 @@
/**
* Writes a terminating zero to a buffer at the current position.
*
- * On successful write, @em neither the position @em nor the size of the buffer is
- * increased.
+ * If successful, sets the size to the current position and advances the position by one.
*
* The purpose of this function is to have the written data ready to be used as
- * a C string.
+ * a C string with the buffer's size being the length of that string.
*
* @param buffer the buffer to write to
* @return zero, if the terminator could be written, non-zero otherwise
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/common.h
--- a/ucx/cx/common.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/common.h Sun Jul 20 22:04:39 2025 +0200
@@ -46,7 +46,7 @@
* Repositories:
* https://sourceforge.net/p/ucx/code
* - or -
- * https://develop.uap-core.de/hg/ucx
+ * https://uap-core.de/hg/ucx
*
*
* LICENCE
@@ -150,7 +150,7 @@
*/
#define cx_attr_malloc __attribute__((__malloc__))
-#ifndef __clang__
+#if !defined(__clang__) && __GNUC__ >= 11
/**
* The pointer returned by the attributed function is supposed to be freed
* by @p freefunc.
@@ -240,20 +240,6 @@
*/
#define cx_attr_access_w(...) cx_attr_access(__write_only__, __VA_ARGS__)
-#if __STDC_VERSION__ >= 202300L
-
-/**
- * Do not warn about unused variable.
- */
-#define cx_attr_unused [[maybe_unused]]
-
-/**
- * Warn about discarded return value.
- */
-#define cx_attr_nodiscard [[nodiscard]]
-
-#else // no C23
-
/**
* Do not warn about unused variable.
*/
@@ -264,8 +250,6 @@
*/
#define cx_attr_nodiscard __attribute__((__warn_unused_result__))
-#endif // __STDC_VERSION__
-
// ---------------------------------------------------------------------------
// MSVC specifics
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/hash_map.h
--- a/ucx/cx/hash_map.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/hash_map.h Sun Jul 20 22:04:39 2025 +0200
@@ -77,7 +77,7 @@
* In other words, when the iterator is finished, @c index==size .
*
* @param allocator the allocator to use
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param itemsize the size of one element
* @param buckets the initial number of buckets in this hash map
* @return a pointer to the new hash map
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/linked_list.h
--- a/ucx/cx/linked_list.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/linked_list.h Sun Jul 20 22:04:39 2025 +0200
@@ -51,7 +51,7 @@
* to cx_cmp_ptr(), if none is given.
*
* @param allocator the allocator for allocating the list nodes
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param comparator the comparator for the elements
* (if @c NULL, and the list is not storing pointers, sort and find
* functions will not work)
@@ -77,7 +77,7 @@
*
* If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
* copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * to cx_cmp_ptr().
*
* @param elem_size (@c size_t) the size of each element in bytes
* @return (@c CxList*) the created list
@@ -393,7 +393,7 @@
* @li @p loc_next and @p loc_prev (ancestor node is determined by using the prev pointer, overall O(1) performance)
* @li @p loc_next and @p begin (ancestor node is determined by list traversal, overall O(n) performance)
*
- * @remark The @c next and @c prev pointers of the removed node are not cleared by this function and may still be used
+ * @remark The @c next and @c prev pointers of the removed chain are not cleared by this function and may still be used
* to traverse to a former adjacent node in the list, or within the chain.
*
* @param begin a pointer to the beginning node pointer (optional)
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/list.h
--- a/ucx/cx/list.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/list.h Sun Jul 20 22:04:39 2025 +0200
@@ -80,8 +80,10 @@
/**
* Member function for inserting a single element.
+ * The data pointer may be @c NULL in which case the function shall only allocate memory.
+ * Returns a pointer to the data of the inserted element.
*/
- int (*insert_element)(
+ void *(*insert_element)(
struct cx_list_s *list,
size_t index,
const void *data
@@ -203,6 +205,22 @@
};
/**
+ * Common type for all list implementations.
+ */
+typedef struct cx_list_s CxList;
+
+/**
+ * A shared instance of an empty list.
+ *
+ * Writing to that list is not allowed.
+ *
+ * You can use this is a placeholder for initializing CxList pointers
+ * for which you do not want to reserve memory right from the beginning.
+ */
+cx_attr_export
+extern CxList *const cxEmptyList;
+
+/**
* Default implementation of an array insert.
*
* This function uses the element insert function for each element of the array.
@@ -336,11 +354,6 @@
);
/**
- * Common type for all list implementations.
- */
-typedef struct cx_list_s CxList;
-
-/**
* Returns the number of elements currently stored in the list.
*
* @param list the list
@@ -359,6 +372,7 @@
* @retval zero success
* @retval non-zero memory allocation failure
* @see cxListAddArray()
+ * @see cxListEmplace()
*/
cx_attr_nonnull
static inline int cxListAdd(
@@ -366,7 +380,7 @@
const void *elem
) {
list->collection.sorted = false;
- return list->cl->insert_element(list, list->collection.size, elem);
+ return list->cl->insert_element(list, list->collection.size, elem) == NULL;
}
/**
@@ -407,6 +421,7 @@
* @retval non-zero memory allocation failure or the index is out of bounds
* @see cxListInsertAfter()
* @see cxListInsertBefore()
+ * @see cxListEmplaceAt()
*/
cx_attr_nonnull
static inline int cxListInsert(
@@ -415,7 +430,41 @@
const void *elem
) {
list->collection.sorted = false;
- return list->cl->insert_element(list, index, elem);
+ return list->cl->insert_element(list, index, elem) == NULL;
+}
+
+/**
+ * Allocates memory for an element at the specified index and returns a pointer to that memory.
+ *
+ * @remark When the list is storing pointers, this will return a @c void**.
+ *
+ * @param list the list
+ * @param index the index where to emplace the element
+ * @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
+ * @see cxListEmplace()
+ * @see cxListInsert()
+ */
+cx_attr_nonnull
+static inline void *cxListEmplaceAt(CxList *list, size_t index) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, index, NULL);
+}
+
+
+/**
+ * Allocates memory for an element at the end of the list and returns a pointer to that memory.
+ *
+ * @remark When the list is storing pointers, this will return a @c void**.
+ *
+ * @param list the list
+ * @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
+ * @see cxListEmplaceAt()
+ * @see cxListAdd()
+ */
+cx_attr_nonnull
+static inline void *cxListEmplace(CxList *list) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, list->collection.size, NULL);
}
/**
@@ -571,8 +620,9 @@
/**
* Removes and returns the element at the specified index.
*
- * No destructor is called and instead the element is copied to the
+ * No destructor is called, and instead the element is copied to the
* @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
*
* @param list the list
* @param index the index of the element
@@ -591,11 +641,93 @@
}
/**
+ * Removes and returns the first element of the list.
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list the list
+ * @param targetbuf a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListPopFront()
+ * @see cxListRemoveAndGetLast()
+ */
+cx_attr_nonnull
+cx_attr_access_w(2)
+static inline int cxListRemoveAndGetFirst(
+ CxList *list,
+ void *targetbuf
+) {
+ return list->cl->remove(list, 0, 1, targetbuf) == 0;
+}
+
+/**
+ * Removes and returns the first element of the list.
+ *
+ * Alias for cxListRemoveAndGetFirst().
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list (@c CxList*) the list
+ * @param targetbuf (@c void*) a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListRemoveAndGetFirst()
+ * @see cxListPop()
+ */
+#define cxListPopFront(list, targetbuf) cxListRemoveAndGetFirst((list), (targetbuf))
+
+
+/**
+ * Removes and returns the last element of the list.
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list the list
+ * @param targetbuf a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ */
+cx_attr_nonnull
+cx_attr_access_w(2)
+static inline int cxListRemoveAndGetLast(
+ CxList *list,
+ void *targetbuf
+) {
+ // note: index may wrap - member function will catch that
+ return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
+}
+
+/**
+ * Removes and returns the last element of the list.
+ *
+ * Alias for cxListRemoveAndGetLast().
+ *
+ * No destructor is called, and instead the element is copied to the
+ * @p targetbuf which MUST be large enough to hold the removed element.
+ * If the list is storing pointers, only the pointer is copied to @p targetbuf.
+ *
+ * @param list (@c CxList*) the list
+ * @param targetbuf (@c void*) a buffer where to copy the element
+ * @retval zero success
+ * @retval non-zero list is empty
+ * @see cxListRemoveAndGetLast()
+ * @see cxListPopFront()
+ */
+#define cxListPop(list, targetbuf) cxListRemoveAndGetLast((list), (targetbuf))
+
+/**
* Removes multiple element starting at the specified index.
*
* If an element destructor function is specified, it is called for each
* element. It is guaranteed that the destructor is called before removing
- * the element, however, due to possible optimizations it is neither guaranteed
+ * the element. However, due to possible optimizations, it is neither guaranteed
* that the destructors are invoked for all elements before starting to remove
* them, nor that the element is removed immediately after the destructor call
* before proceeding to the next element.
@@ -615,10 +747,11 @@
}
/**
- * Removes and returns multiple element starting at the specified index.
+ * Removes and returns multiple elements starting at the specified index.
*
- * No destructor is called and instead the elements are copied to the
+ * No destructor is called, and instead the elements are copied to the
* @p targetbuf which MUST be large enough to hold all removed elements.
+ * If the list is storing pointers, @p targetbuf is expected to be an array of pointers.
*
* @param list the list
* @param index the index of the element
@@ -654,15 +787,15 @@
/**
* Swaps two items in the list.
*
- * Implementations should only allocate temporary memory for the swap, if
+ * Implementations should only allocate temporary memory for the swap if
* it is necessary.
*
* @param list the list
* @param i the index of the first element
* @param j the index of the second element
* @retval zero success
- * @retval non-zero one of the indices is out of bounds
- * or the swap needed extra memory but allocation failed
+ * @retval non-zero one of the indices is out of bounds,
+ * or the swap needed extra memory, but allocation failed
*/
cx_attr_nonnull
static inline int cxListSwap(
@@ -677,6 +810,8 @@
/**
* Returns a pointer to the element at the specified index.
*
+ * If the list is storing pointers, returns the pointer stored at the specified index.
+ *
* @param list the list
* @param index the index of the element
* @return a pointer to the element or @c NULL if the index is out of bounds
@@ -690,6 +825,49 @@
}
/**
+ * Returns a pointer to the first element.
+ *
+ * If the list is storing pointers, returns the first pointer stored in the list.
+ *
+ * @param list the list
+ * @return a pointer to the first element or @c NULL if the list is empty
+ */
+cx_attr_nonnull
+static inline void *cxListFirst(const CxList *list) {
+ return list->cl->at(list, 0);
+}
+
+/**
+ * Returns a pointer to the last element.
+ *
+ * If the list is storing pointers, returns the last pointer stored in the list.
+ *
+ * @param list the list
+ * @return a pointer to the last element or @c NULL if the list is empty
+ */
+cx_attr_nonnull
+static inline void *cxListLast(const CxList *list) {
+ return list->cl->at(list, list->collection.size - 1);
+}
+
+/**
+ * Sets the element at the specified index in the list
+ *
+ * @param list the list to set the element in
+ * @param index the index to set the element at
+ * @param elem element to set
+ * @retval zero on success
+ * @retval non-zero when index is out of bounds
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxListSet(
+ CxList *list,
+ size_t index,
+ const void *elem
+);
+
+/**
* Returns an iterator pointing to the item at the specified index.
*
* The returned iterator is position-aware.
@@ -773,14 +951,14 @@
*
* The returned iterator is position-aware.
*
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
static inline CxIterator cxListIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
return list->cl->iterator(list, 0, false);
}
@@ -789,14 +967,14 @@
*
* The returned iterator is position-aware.
*
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
static inline CxIterator cxListMutIterator(CxList *list) {
+ if (list == NULL) list = cxEmptyList;
return cxListMutIteratorAt(list, 0);
}
@@ -806,14 +984,14 @@
*
* The returned iterator is position-aware.
*
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
static inline CxIterator cxListBackwardsIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
return list->cl->iterator(list, list->collection.size - 1, true);
}
@@ -822,14 +1000,14 @@
*
* The returned iterator is position-aware.
*
- * If the list is empty, a past-the-end iterator will be returned.
+ * If the list is empty or @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
+ if (list == NULL) list = cxEmptyList;
return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
}
@@ -842,6 +1020,7 @@
* @param elem the element to find
* @return the index of the element or the size of the list when the element is not found
* @see cxListIndexValid()
+ * @see cxListContains()
*/
cx_attr_nonnull
cx_attr_nodiscard
@@ -853,6 +1032,26 @@
}
/**
+ * Checks, if the list contains the specified element.
+ *
+ * The elements are compared with the list's comparator function.
+ *
+ * @param list the list
+ * @param elem the element to find
+ * @retval true if the element is contained
+ * @retval false if the element is not contained
+ * @see cxListFind()
+ */
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline bool cxListContains(
+ const CxList* list,
+ const void* elem
+) {
+ return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
+}
+
+/**
* Checks if the specified index is within bounds.
*
* @param list the list
@@ -894,6 +1093,7 @@
*/
cx_attr_nonnull
static inline void cxListSort(CxList *list) {
+ if (list->collection.sorted) return;
list->cl->sort(list);
list->collection.sorted = true;
}
@@ -942,17 +1142,6 @@
cx_attr_export
void cxListFree(CxList *list);
-/**
- * A shared instance of an empty list.
- *
- * Writing to that list is not allowed.
- *
- * You can use this is a placeholder for initializing CxList pointers
- * for which you do not want to reserve memory right from the beginning.
- */
-cx_attr_export
-extern CxList *const cxEmptyList;
-
#ifdef __cplusplus
} // extern "C"
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/mempool.h
--- a/ucx/cx/mempool.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/mempool.h Sun Jul 20 22:04:39 2025 +0200
@@ -43,31 +43,107 @@
extern "C" {
#endif
-/** Internal structure for pooled memory. */
-struct cx_mempool_memory_s;
+/** A memory block in a simple memory pool. */
+struct cx_mempool_memory_s {
+ /** The destructor. */
+ cx_destructor_func destructor;
+ /** The actual memory. */
+ char c[];
+};
+
+/** A memory block in an advanced memory pool. */
+struct cx_mempool_memory2_s {
+ /** The destructor. */
+ cx_destructor_func2 destructor;
+ /** Data for the destructor. */
+ void *data;
+ /** The actual memory. */
+ char c[];
+};
+
+/** Represents memory that is not allocated by, but registered with a pool. */
+struct cx_mempool_foreign_memory_s {
+ /** The foreign memory. */
+ void* mem;
+ union {
+ /** Simple destructor. */
+ cx_destructor_func destr;
+ /** Advanced destructor. */
+ cx_destructor_func2 destr2;
+ };
+ /** Data for the advanced destructor. */
+ void *destr2_data;
+};
+
+/** Specifies how individual blocks are allocated. */
+enum cx_mempool_type {
+ /**
+ * Allows registration of cx_destructor_func for each memory block.
+ */
+ CX_MEMPOOL_TYPE_SIMPLE,
+ /**
+ * Allows registration of cx_destructor_func2 for each memory block.
+ */
+ CX_MEMPOOL_TYPE_ADVANCED,
+ /**
+ * No individual destructor registration allowed.
+ *
+ * In this mode, no additional memory per block is allocated.
+ */
+ CX_MEMPOOL_TYPE_PURE,
+};
/**
* The basic structure of a memory pool.
* Should be the first member of an actual memory pool implementation.
*/
struct cx_mempool_s {
+ /** The used allocator, initialized with the cxDefaultAllocator. */
+ const CxAllocator * const base_allocator;
+
/** The provided allocator. */
const CxAllocator *allocator;
- /**
- * A destructor that shall be automatically registered for newly allocated memory.
- * This destructor MUST NOT free the memory.
- */
- cx_destructor_func auto_destr;
-
/** Array of pooled memory. */
- struct cx_mempool_memory_s **data;
+ void **data;
/** Number of pooled memory items. */
size_t size;
/** Memory pool capacity. */
size_t capacity;
+
+ /** Array of registered memory. */
+ struct cx_mempool_foreign_memory_s *registered;
+
+ /** Number of registered memory items. */
+ size_t registered_size;
+
+ /** Capacity for registered memory. */
+ size_t registered_capacity;
+
+ /**
+ * A destructor that shall be called before deallocating a memory block.
+ * This destructor MUST NOT free the memory itself.
+ *
+ * It is guaranteed that this destructor is called after the individual
+ * destructor of the memory block and before @c destr2.
+ */
+ cx_destructor_func destr;
+
+ /**
+ * A destructor that shall be called before deallocating a memory block.
+ * This destructor MUST NOT free the memory itself.
+ *
+ * It is guaranteed that this destructor is called after the individual
+ * destructor of the memory block and @c destr.
+ */
+ cx_destructor_func2 destr2;
+
+ /**
+ * Additional data for the @c destr2.
+ */
+ void *destr2_data;
};
/**
@@ -84,31 +160,76 @@
void cxMempoolFree(CxMempool *pool);
/**
- * Creates an array-based memory pool with a shared destructor function.
+ * Creates an array-based memory pool.
*
- * This destructor MUST NOT free the memory.
+ * The type determines how much additional memory is allocated per block
+ * to register a destructor function.
*
- * @param capacity the initial capacity of the pool
- * @param destr optional destructor function to use for allocated memory
+ * @param capacity the initial capacity of the pool (an implementation default if zero)
+ * @param type the type of memory pool
* @return the created memory pool or @c NULL if allocation failed
*/
cx_attr_nodiscard
cx_attr_malloc
cx_attr_dealloc(cxMempoolFree, 1)
cx_attr_export
-CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func destr);
+CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
+
+/**
+ * Creates a basic array-based memory pool.
+ *
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_SIMPLE.
+ *
+ * @param capacity (@c size_t) the initial capacity of the pool
+ * @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
+ */
+#define cxMempoolCreateSimple(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_SIMPLE)
+
+/**
+ * Creates a basic array-based memory pool.
+ *
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_ADVANCED.
+ *
+ * @param capacity (@c size_t) the initial capacity of the pool
+ * @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
+ */
+#define cxMempoolCreateAdvanced(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_ADVANCED)
/**
* Creates a basic array-based memory pool.
*
+ * Convenience macro to create a memory pool of type #CX_MEMPOOL_TYPE_PURE.
+ *
* @param capacity (@c size_t) the initial capacity of the pool
* @return (@c CxMempool*) the created memory pool or @c NULL if allocation failed
*/
-#define cxMempoolCreateSimple(capacity) cxMempoolCreate(capacity, NULL)
+#define cxMempoolCreatePure(capacity) cxMempoolCreate(capacity, CX_MEMPOOL_TYPE_PURE)
+
+/**
+ * Sets the global destructor for all memory blocks within the specified pool.
+ *
+ * @param pool the memory pool
+ * @param fnc the destructor that shall be applied to all memory blocks
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
+
+/**
+ * Sets the global destructor for all memory blocks within the specified pool.
+ *
+ * @param pool the memory pool
+ * @param fnc the destructor that shall be applied to all memory blocks
+ * @param data additional data for the destructor function
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
/**
* Sets the destructor function for a specific allocated memory object.
*
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_SIMPLE, the behavior is undefined.
* If the memory is not managed by a UCX memory pool, the behavior is undefined.
* The destructor MUST NOT free the memory.
*
@@ -123,10 +244,29 @@
);
/**
+ * Sets the destructor function for a specific allocated memory object.
+ *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_ADVANCED, the behavior is undefined.
+ * If the memory is not managed by a UCX memory pool, the behavior is undefined.
+ * The destructor MUST NOT free the memory.
+ *
+ * @param memory the object allocated in the pool
+ * @param fnc the destructor function
+ * @param data additional data for the destructor function
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxMempoolSetDestructor2(
+ void *memory,
+ cx_destructor_func2 fnc,
+ void *data
+);
+
+/**
* Removes the destructor function for a specific allocated memory object.
*
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_SIMPLE, the behavior is undefined.
* If the memory is not managed by a UCX memory pool, the behavior is undefined.
- * The destructor MUST NOT free the memory.
*
* @param memory the object allocated in the pool
*/
@@ -135,12 +275,25 @@
void cxMempoolRemoveDestructor(void *memory);
/**
+ * Removes the destructor function for a specific allocated memory object.
+ *
+ * If the type of memory pool is not #CX_MEMPOOL_TYPE_ADVANCED, the behavior is undefined.
+ * If the memory is not managed by a UCX memory pool, the behavior is undefined.
+ *
+ * @param memory the object allocated in the pool
+ */
+cx_attr_nonnull
+cx_attr_export
+void cxMempoolRemoveDestructor2(void *memory);
+
+/**
* Registers foreign memory with this pool.
*
* The destructor, in contrast to memory allocated by the pool, MUST free the memory.
+ * This function can be used with any pool of any type, since destructors for registered memory
+ * are entirely independent of the pool's memory management.
*
- * A small portion of memory will be allocated to register the information in the pool.
- * If that allocation fails, this function will return non-zero.
+ * The destructor for the registered memory will be called after all pooled items have been freed.
*
* @param pool the pool
* @param memory the object to register (MUST NOT be already allocated in the pool)
@@ -156,6 +309,79 @@
cx_destructor_func destr
);
+
+/**
+ * Registers foreign memory with this pool.
+ *
+ * The destructor, in contrast to memory allocated by the pool, MUST free the memory.
+ * This function can be used with any pool of any type, since destructors for registered memory
+ * are entirely independent of the pool's memory management.
+ *
+ * The destructor for the registered memory will be called after all pooled items have been freed.
+ *
+ * @attention The data pointer MUST NOT be @c NULL.
+ * If you wish to register a destructor without additional data, use cxMempoolRegister().
+ *
+ * @param pool the pool
+ * @param memory the object to register (MUST NOT be already allocated in the pool)
+ * @param destr the destructor function
+ * @param data additional data for the destructor function
+ * @retval zero success
+ * @retval non-zero failure
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolRegister2(
+ CxMempool *pool,
+ void *memory,
+ cx_destructor_func2 destr,
+ void *data
+);
+
+/**
+ * Transfers all the memory managed by one pool to another.
+ *
+ * The allocator of the source pool will also be transferred and registered with the destination pool
+ * and stays valid, as long as the destination pool is not destroyed.
+ *
+ * The source pool will get a completely new allocator and can be reused or destroyed afterward.
+ *
+ * This function fails when the destination pool has a different type than the source pool.
+ *
+ * @param source the pool to move the memory from
+ * @param dest the pool where to transfer the memory to
+ * @retval zero success
+ * @retval non-zero allocation failure or incompatible pools
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolTransfer(
+ CxMempool *source,
+ CxMempool *dest
+);
+
+/**
+ * Transfers an object from one pool to another.
+ *
+ * This function fails when the destination pool has a different type than the source pool.
+ *
+ * @attention If the object maintains a reference to the pool's allocator,
+ * you must make sure to update that reference to the allocator of the destination pool.
+ *
+ * @param source the pool to move the memory from
+ * @param dest the pool where to transfer the memory to
+ * @param obj pointer to the object that shall be transferred
+ * @retval zero success
+ * @retval non-zero failure, or the object was not found in the source pool, or the pools are incompatible
+ */
+cx_attr_nonnull
+cx_attr_export
+int cxMempoolTransferObject(
+ CxMempool *source,
+ CxMempool *dest,
+ const void *obj
+);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/printf.h
--- a/ucx/cx/printf.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/printf.h Sun Jul 20 22:04:39 2025 +0200
@@ -229,7 +229,7 @@
cx_attr_cstr_arg(4)
cx_attr_export
int cx_sprintf_a(
- CxAllocator *alloc,
+ const CxAllocator *alloc,
char **str,
size_t *len,
const char *fmt,
@@ -274,7 +274,7 @@
cx_attr_access_rw(3)
cx_attr_export
int cx_vsprintf_a(
- CxAllocator *alloc,
+ const CxAllocator *alloc,
char **str,
size_t *len,
const char *fmt,
@@ -333,7 +333,7 @@
cx_attr_access_rw(4)
cx_attr_export
int cx_sprintf_sa(
- CxAllocator *alloc,
+ const CxAllocator *alloc,
char *buf,
size_t *len,
char **str,
@@ -388,7 +388,7 @@
cx_attr_cstr_arg(5)
cx_attr_export
int cx_vsprintf_sa(
- CxAllocator *alloc,
+ const CxAllocator *alloc,
char *buf,
size_t *len,
char **str,
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/properties.h
--- a/ucx/cx/properties.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/properties.h Sun Jul 20 22:04:39 2025 +0200
@@ -551,10 +551,12 @@
/**
* Creates a properties sink for an UCX map.
*
- * The values stored in the map will be pointers to strings allocated
- * by #cx_strdup_a().
- * The default stdlib allocator will be used, unless you specify a custom
- * allocator in the optional @c data of the sink.
+ * The values stored in the map will be pointers to freshly allocated,
+ * zero-terminated C strings (@c char*), which means the @p map should have been
+ * created with #CX_STORE_POINTERS.
+ *
+ * The cxDefaultAllocator will be used unless you specify a custom
+ * allocator in the optional @c data field of the returned sink.
*
* @param map the map that shall consume the k/v-pairs.
* @return the sink
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/string.h
--- a/ucx/cx/string.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/string.h Sun Jul 20 22:04:39 2025 +0200
@@ -39,6 +39,12 @@
#include "common.h"
#include "allocator.h"
+/** Expands a UCX string as printf arguments. */
+#define CX_SFMT(s) (int) (s).length, (s).ptr
+
+/** Format specifier for a UCX string */
+#define CX_PRIstr ".*s"
+
/**
* The maximum length of the "needle" in cx_strstr() that can use SBO.
*/
@@ -151,7 +157,7 @@
*
* @param literal the string literal
*/
-#define CX_STR(literal) (cxstring){literal, sizeof(literal) - 1}
+#define CX_STR(literal) ((cxstring){literal, sizeof(literal) - 1})
#endif
@@ -299,7 +305,7 @@
#endif
/**
- * Passes the pointer in this string to @c free().
+ * Passes the pointer in this string to the cxDefaultAllocator's @c free() function.
*
* The pointer in the struct is set to @c NULL and the length is set to zero
* which means that this function protects you against double-free.
@@ -334,6 +340,46 @@
);
/**
+ * Copies a string.
+ *
+ * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
+ * source string, including a zero-terminator.
+ *
+ * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
+ *
+ * @param alloc the allocator
+ * @param dest a pointer to the structure where to copy the contents to
+ * @param src the source string
+ *
+ * @retval zero success
+ * @retval non-zero if re-allocation failed
+ */
+cx_attr_nonnull_arg(1)
+cx_attr_export
+int cx_strcpy_a(
+ const CxAllocator *alloc,
+ cxmutstr *dest,
+ cxstring src
+);
+
+
+/**
+ * Copies a string.
+ *
+ * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
+ * source string, including a zero-terminator.
+ *
+ * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
+ *
+ * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to
+ * @param src (@c cxstring) the source string
+ *
+ * @retval zero success
+ * @retval non-zero if re-allocation failed
+ */
+#define cx_strcpy(dest, src) cx_strcpy_a(cxDefaultAllocator, dest, src)
+
+/**
* Returns the accumulated length of all specified strings.
*
* If this sum overflows, errno is set to EOVERFLOW.
@@ -408,7 +454,7 @@
/**
* Concatenates strings and returns a new string.
*
- * The resulting string will be allocated by standard @c malloc().
+ * The resulting string will be allocated by the cxDefaultAllocator.
* So developers @em must pass the return value to cx_strfree() eventually.
*
* If memory allocation fails, the pointer in the returned string will
@@ -428,7 +474,7 @@
/**
* Concatenates strings.
*
- * The resulting string will be allocated by standard @c malloc().
+ * The resulting string will be allocated by the cxDefaultAllocator.
* So developers @em must pass the return value to cx_strfree() eventually.
*
* If @p str already contains a string, the memory will be reallocated and
@@ -879,13 +925,13 @@
* @see cx_strfree_a()
*/
#define cx_strdup_a(allocator, string) \
- cx_strdup_a_((allocator), cx_strcast((string)))
+ cx_strdup_a_((allocator), cx_strcast(string))
/**
* Creates a duplicate of the specified string.
*
- * The new string will contain a copy allocated by standard
- * @c malloc(). So developers @em must pass the return value to cx_strfree().
+ * The new string will contain a copy allocated by the cxDefaultAllocator.
+ * So developers @em must pass the return value to cx_strfree().
*
* @note The returned string is guaranteed to be zero-terminated.
*
@@ -894,7 +940,7 @@
* @see cx_strdup_a()
* @see cx_strfree()
*/
-#define cx_strdup(string) cx_strdup_a_(cxDefaultAllocator, string)
+#define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string)
/**
* Omits leading and trailing spaces.
@@ -1016,7 +1062,7 @@
*
* Replaces at most @p replmax occurrences.
*
- * The returned string will be allocated by @c malloc() and is guaranteed
+ * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
* to be zero-terminated.
*
* If allocation fails, or the input string is empty,
@@ -1052,7 +1098,7 @@
/**
* Replaces a string with another string.
*
- * The returned string will be allocated by @c malloc() and is guaranteed
+ * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
* to be zero-terminated.
*
* If allocation fails, or the input string is empty,
@@ -1091,7 +1137,7 @@
* @return (@c CxStrtokCtx) a new string tokenization context
*/
#define cx_strtok(str, delim, limit) \
- cx_strtok_(cx_strcast((str)), cx_strcast((delim)), (limit))
+ cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
/**
* Returns the next token.
diff -r b34bd1557c6c -r 77254bd6dccb ucx/cx/tree.h
--- a/ucx/cx/tree.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/cx/tree.h Sun Jul 20 22:04:39 2025 +0200
@@ -120,6 +120,7 @@
size_t stack_size;
/**
* The current depth in the tree.
+ * The node with which the iteration starts has depth 1.
*/
size_t depth;
};
@@ -135,6 +136,7 @@
void *node;
/**
* The depth of the node.
+ * The first visited node has depth 1.
*/
size_t depth;
/**
@@ -211,7 +213,7 @@
*/
cx_attr_nonnull
static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
- free(iter->stack);
+ cxFreeDefault(iter->stack);
iter->stack = NULL;
}
@@ -224,7 +226,7 @@
struct cx_tree_visitor_queue_s *q = visitor->queue_next;
while (q != NULL) {
struct cx_tree_visitor_queue_s *next = q->next;
- free(q);
+ cxFreeDefault(q);
q = next;
}
}
@@ -441,7 +443,7 @@
* Creates a depth-first iterator for a tree with the specified root node.
*
* @note A tree iterator needs to maintain a stack of visited nodes, which is
- * allocated using stdlib malloc().
+ * allocated using the cxDefaultAllocator.
* When the iterator becomes invalid, this memory is automatically released.
* However, if you wish to cancel the iteration before the iterator becomes
* invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
@@ -469,8 +471,8 @@
/**
* Creates a breadth-first iterator for a tree with the specified root node.
*
- * @note A tree visitor needs to maintain a queue of to be visited nodes, which
- * is allocated using stdlib malloc().
+ * @note A tree visitor needs to maintain a queue of to-be visited nodes, which
+ * is allocated using the cxDefaultAllocator.
* When the visitor becomes invalid, this memory is automatically released.
* However, if you wish to cancel the iteration before the visitor becomes
* invalid by itself, you MUST call cxTreeVisitorDispose() manually to release
@@ -956,7 +958,7 @@
* will free the nodes with the allocator's free() method.
*
* @param allocator the allocator that shall be used
- * (if @c NULL, a default stdlib allocator will be used)
+ * (if @c NULL, the cxDefaultAllocator will be used)
* @param create_func a function that creates new nodes
* @param search_func a function that compares two nodes
* @param search_data_func a function that compares a node with data
@@ -1020,7 +1022,7 @@
* tree, you need to specify those functions afterwards.
*
* @param allocator the allocator that was used for nodes of the wrapped tree
- * (if @c NULL, a default stdlib allocator is assumed)
+ * (if @c NULL, the cxDefaultAllocator is assumed)
* @param root the root node of the tree that shall be wrapped
* @param loc_parent offset in the node struct for the parent pointer
* @param loc_children offset in the node struct for the children linked list
@@ -1188,6 +1190,18 @@
size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
/**
+ * Determines the size of the entire tree.
+ *
+ * @param tree the tree
+ * @return the tree size, counting the root as one
+ */
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline size_t cxTreeSize(CxTree *tree) {
+ return tree->size;
+}
+
+/**
* Determines the depth of the entire tree.
*
* @param tree the tree
diff -r b34bd1557c6c -r 77254bd6dccb ucx/json.c
--- a/ucx/json.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/json.c Sun Jul 20 22:04:39 2025 +0200
@@ -500,7 +500,7 @@
if (all_printable && escape) {
size_t capa = str.length + 32;
- char *space = malloc(capa);
+ 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);
@@ -631,10 +631,10 @@
void cxJsonDestroy(CxJson *json) {
cxBufferDestroy(&json->buffer);
if (json->states != json->states_internal) {
- free(json->states);
+ cxFreeDefault(json->states);
}
if (json->vbuf != json->vbuf_internal) {
- free(json->vbuf);
+ cxFreeDefault(json->vbuf);
}
cxJsonValueFree(json->parsed);
json->parsed = NULL;
@@ -984,67 +984,67 @@
if (values[i] == NULL) break;
cxJsonValueFree(values[i]);
}
- free(values);
+ cxFreeDefault(values);
}
// LCOV_EXCL_STOP
int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) {
- CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+ CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
values[i] = cxJsonCreateNumber(arr->allocator, num[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
- free(values);
+ cxFreeDefault(values);
return ret;
}
int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) {
- CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+ CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
values[i] = cxJsonCreateInteger(arr->allocator, num[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
- free(values);
+ cxFreeDefault(values);
return ret;
}
int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) {
- CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+ CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
values[i] = cxJsonCreateString(arr->allocator, str[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
- free(values);
+ cxFreeDefault(values);
return ret;
}
int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) {
- CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+ CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
values[i] = cxJsonCreateCxString(arr->allocator, str[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
- free(values);
+ cxFreeDefault(values);
return ret;
}
int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) {
- CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
+ CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
- free(values);
+ cxFreeDefault(values);
return ret;
}
diff -r b34bd1557c6c -r 77254bd6dccb ucx/linked_list.c
--- a/ucx/linked_list.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/linked_list.c Sun Jul 20 22:04:39 2025 +0200
@@ -401,7 +401,7 @@
) {
void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE];
void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ?
- malloc(sizeof(void *) * length) : sbo;
+ cxMallocDefault(sizeof(void *) * length) : sbo;
if (sorted == NULL) abort();
void *rc, *lc;
@@ -439,7 +439,7 @@
*begin = sorted[0];
*end = sorted[length - 1];
if (sorted != sbo) {
- free(sorted);
+ cxFreeDefault(sorted);
}
}
@@ -613,7 +613,9 @@
// initialize new new_node
new_node->prev = new_node->next = NULL;
- memcpy(new_node->payload, elem, list->collection.elem_size);
+ if (elem != NULL) {
+ memcpy(new_node->payload, elem, list->collection.elem_size);
+ }
// insert
cx_linked_list *ll = (cx_linked_list *) list;
@@ -659,12 +661,26 @@
return n;
}
-static int cx_ll_insert_element(
+static void *cx_ll_insert_element(
struct cx_list_s *list,
size_t index,
const void *element
) {
- return 1 != cx_ll_insert_array(list, index, element, 1);
+ // out-of-bounds check
+ if (index > list->collection.size) return NULL;
+
+ // find position efficiently
+ cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
+
+ // perform first insert
+ if (cx_ll_insert_at(list, node, element)) return NULL;
+
+ // return a pointer to the data of the inserted node
+ if (node == NULL) {
+ return ((cx_linked_list *) list)->begin->payload;
+ } else {
+ return node->next->payload;
+ }
}
static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func;
@@ -920,6 +936,8 @@
const void *elem,
bool remove
) {
+ if (list->collection.size == 0) return 0;
+
size_t index;
cx_linked_list *ll = ((cx_linked_list *) list);
cx_linked_list_node *node = cx_linked_list_find(
@@ -1054,12 +1072,12 @@
}
return result;
} else {
- int result = cx_ll_insert_element(list, list->collection.size, elem);
- if (result == 0) {
- iter->elem_count++;
- iter->index = list->collection.size;
+ if (cx_ll_insert_element(list, list->collection.size, elem) == NULL) {
+ return 1;
}
- return result;
+ iter->elem_count++;
+ iter->index = list->collection.size;
+ return 0;
}
}
diff -r b34bd1557c6c -r 77254bd6dccb ucx/list.c
--- a/ucx/list.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/list.c Sun Jul 20 22:04:39 2025 +0200
@@ -62,7 +62,7 @@
list->climpl->deallocate(list);
}
-static int cx_pl_insert_element(
+static void *cx_pl_insert_element(
struct cx_list_s *list,
size_t index,
const void *element
@@ -282,7 +282,7 @@
const char *src = data;
size_t i = 0;
for (; i < n; i++) {
- if (0 != invoke_list_func(
+ if (NULL == invoke_list_func(
insert_element, list, index + i,
src + (i * elem_size))) return i;
}
@@ -329,7 +329,7 @@
// insert the elements at location si
if (ins == 1) {
- if (0 != invoke_list_func(
+ if (NULL == invoke_list_func(
insert_element, list, di, src)) return inserted;
} else {
size_t r = invoke_list_func(insert_array, list, di, src, ins);
@@ -354,7 +354,7 @@
void cx_list_default_sort(struct cx_list_s *list) {
size_t elem_size = list->collection.elem_size;
size_t list_size = list->collection.size;
- void *tmp = malloc(elem_size * list_size);
+ void *tmp = cxMallocDefault(elem_size * list_size);
if (tmp == NULL) abort();
// copy elements from source array
@@ -377,7 +377,7 @@
loc += elem_size;
}
- free(tmp);
+ cxFreeDefault(tmp);
}
int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
@@ -387,7 +387,7 @@
size_t elem_size = list->collection.elem_size;
- void *tmp = malloc(elem_size);
+ void *tmp = cxMallocDefault(elem_size);
if (tmp == NULL) return 1;
void *ip = invoke_list_func(at, list, i);
@@ -397,7 +397,7 @@
memcpy(ip, jp, elem_size);
memcpy(jp, tmp, elem_size);
- free(tmp);
+ cxFreeDefault(tmp);
return 0;
}
@@ -494,3 +494,24 @@
if (list == NULL) return;
list->cl->deallocate(list);
}
+
+int cxListSet(
+ CxList *list,
+ size_t index,
+ const void *elem
+) {
+ if (index >= list->collection.size) {
+ return 1;
+ }
+
+ if (list->collection.store_pointer) {
+ // For pointer collections, always use climpl
+ void **target = list->climpl->at(list, index);
+ *target = (void *)elem;
+ } else {
+ void *target = list->cl->at(list, index);
+ memcpy(target, elem, list->collection.elem_size);
+ }
+
+ return 0;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ucx/mempool.c
--- a/ucx/mempool.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/mempool.c Sun Jul 20 22:04:39 2025 +0200
@@ -31,44 +31,69 @@
#include
#include
-struct cx_mempool_memory_s {
- /** The destructor. */
- cx_destructor_func destructor;
- /** The actual memory. */
- char c[];
-};
+static int cx_mempool_ensure_capacity(
+ struct cx_mempool_s *pool,
+ size_t needed_capacity
+) {
+ if (needed_capacity <= pool->capacity) return 0;
+ size_t newcap = pool->capacity >= 1000 ?
+ pool->capacity + 1000 : pool->capacity * 2;
+ size_t newmsize;
+ // LCOV_EXCL_START
+ if (pool->capacity > newcap
+ || cx_szmul(newcap, sizeof(void*), &newmsize)) {
+ errno = EOVERFLOW;
+ return 1;
+ } // LCOV_EXCL_STOP
+ void **newdata = cxRealloc(pool->base_allocator, pool->data, newmsize);
+ if (newdata == NULL) return 1;
+ pool->data = newdata;
+ pool->capacity = newcap;
+ return 0;
+}
-static void *cx_mempool_malloc(
+static int cx_mempool_ensure_registered_capacity(
+ struct cx_mempool_s *pool,
+ size_t needed_capacity
+) {
+ if (needed_capacity <= pool->registered_capacity) return 0;
+ // we do not expect so many registrations
+ size_t newcap = pool->registered_capacity + 8;
+ size_t newmsize;
+ // LCOV_EXCL_START
+ if (pool->registered_capacity > newcap || cx_szmul(newcap,
+ sizeof(struct cx_mempool_foreign_memory_s), &newmsize)) {
+ errno = EOVERFLOW;
+ return 1;
+ } // LCOV_EXCL_STOP
+ void *newdata = cxRealloc(pool->base_allocator, pool->registered, newmsize);
+ if (newdata == NULL) return 1;
+ pool->registered = newdata;
+ pool->registered_capacity = newcap;
+ return 0;
+}
+
+static void *cx_mempool_malloc_simple(
void *p,
size_t n
) {
struct cx_mempool_s *pool = p;
- if (pool->size >= pool->capacity) {
- size_t newcap = pool->capacity - (pool->capacity % 16) + 16;
- size_t newmsize;
- if (pool->capacity > newcap || cx_szmul(newcap,
- sizeof(struct cx_mempool_memory_s*), &newmsize)) {
- errno = EOVERFLOW;
- return NULL;
- }
- struct cx_mempool_memory_s **newdata = realloc(pool->data, newmsize);
- if (newdata == NULL) return NULL;
- pool->data = newdata;
- pool->capacity = newcap;
+ if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+ return NULL; // LCOV_EXCL_LINE
}
- struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
+ struct cx_mempool_memory_s *mem =
+ cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory_s) + n);
if (mem == NULL) return NULL;
-
- mem->destructor = pool->auto_destr;
+ mem->destructor = NULL;
pool->data[pool->size] = mem;
pool->size++;
return mem->c;
}
-static void *cx_mempool_calloc(
+static void *cx_mempool_calloc_simple(
void *p,
size_t nelem,
size_t elsize
@@ -78,53 +103,165 @@
errno = EOVERFLOW;
return NULL;
}
- void *ptr = cx_mempool_malloc(p, msz);
+ void *ptr = cx_mempool_malloc_simple(p, msz);
if (ptr == NULL) return NULL;
memset(ptr, 0, nelem * elsize);
return ptr;
}
-static void *cx_mempool_realloc(
+static void cx_mempool_free_simple(
+ void *p,
+ void *ptr
+) {
+ if (!ptr) return;
+ struct cx_mempool_s *pool = p;
+
+ struct cx_mempool_memory_s *mem =
+ (void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s));
+
+ for (size_t i = 0; i < pool->size; i++) {
+ if (mem == pool->data[i]) {
+ if (mem->destructor) {
+ mem->destructor(mem->c);
+ }
+ if (pool->destr) {
+ pool->destr(mem->c);
+ }
+ if (pool->destr2) {
+ pool->destr2(pool->destr2_data, mem->c);
+ }
+ cxFree(pool->base_allocator, mem);
+ size_t last_index = pool->size - 1;
+ if (i != last_index) {
+ pool->data[i] = pool->data[last_index];
+ pool->data[last_index] = NULL;
+ }
+ pool->size--;
+ return;
+ }
+ }
+ abort(); // LCOV_EXCL_LINE
+}
+
+static void *cx_mempool_realloc_simple(
void *p,
void *ptr,
size_t n
) {
+ if (ptr == NULL) {
+ return cx_mempool_malloc_simple(p, n);
+ }
+ if (n == 0) {
+ cx_mempool_free_simple(p, ptr);
+ return NULL;
+ }
struct cx_mempool_s *pool = p;
- struct cx_mempool_memory_s *mem, *newm;
- mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func));
- newm = realloc(mem, n + sizeof(cx_destructor_func));
+ const unsigned overhead = sizeof(struct cx_mempool_memory_s);
+ struct cx_mempool_memory_s *mem =
+ (void *) (((char *) ptr) - overhead);
+ struct cx_mempool_memory_s *newm =
+ cxRealloc(pool->base_allocator, mem, n + overhead);
if (newm == NULL) return NULL;
if (mem != newm) {
for (size_t i = 0; i < pool->size; i++) {
if (pool->data[i] == mem) {
pool->data[i] = newm;
- return ((char*)newm) + sizeof(cx_destructor_func);
+ return ((char*)newm) + overhead;
}
}
abort(); // LCOV_EXCL_LINE
} else {
- return ptr;
+ // unfortunately glibc() realloc seems to always move
+ return ptr; // LCOV_EXCL_LINE
+ }
+}
+
+static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) {
+ const bool has_destr = pool->destr;
+ const bool has_destr2 = pool->destr2;
+ for (size_t i = 0; i < pool->size; i++) {
+ struct cx_mempool_memory_s *mem = pool->data[i];
+ if (mem->destructor) {
+ mem->destructor(mem->c);
+ }
+ if (has_destr) {
+ pool->destr(mem->c);
+ }
+ if (has_destr2) {
+ pool->destr2(pool->destr2_data, mem->c);
+ }
+ cxFree(pool->base_allocator, mem);
}
}
-static void cx_mempool_free(
+static cx_allocator_class cx_mempool_simple_allocator_class = {
+ cx_mempool_malloc_simple,
+ cx_mempool_realloc_simple,
+ cx_mempool_calloc_simple,
+ cx_mempool_free_simple
+};
+
+static void *cx_mempool_malloc_advanced(
+ void *p,
+ size_t n
+) {
+ struct cx_mempool_s *pool = p;
+
+ if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+ return NULL; // LCOV_EXCL_LINE
+ }
+
+ struct cx_mempool_memory2_s *mem =
+ cxMalloc(pool->base_allocator, sizeof(struct cx_mempool_memory2_s) + n);
+ if (mem == NULL) return NULL;
+ mem->destructor = NULL;
+ mem->data = NULL;
+ pool->data[pool->size] = mem;
+ pool->size++;
+
+ return mem->c;
+}
+
+static void *cx_mempool_calloc_advanced(
+ void *p,
+ size_t nelem,
+ size_t elsize
+) {
+ size_t msz;
+ if (cx_szmul(nelem, elsize, &msz)) {
+ errno = EOVERFLOW;
+ return NULL;
+ }
+ void *ptr = cx_mempool_malloc_advanced(p, msz);
+ if (ptr == NULL) return NULL;
+ memset(ptr, 0, nelem * elsize);
+ return ptr;
+}
+
+static void cx_mempool_free_advanced(
void *p,
void *ptr
) {
if (!ptr) return;
struct cx_mempool_s *pool = p;
- struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *)
- ((char *) ptr - sizeof(cx_destructor_func));
+ struct cx_mempool_memory2_s *mem =
+ (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s));
for (size_t i = 0; i < pool->size; i++) {
if (mem == pool->data[i]) {
if (mem->destructor) {
- mem->destructor(mem->c);
+ mem->destructor(mem->data, mem->c);
+ }
+ if (pool->destr) {
+ pool->destr(mem->c);
}
- free(mem);
+ if (pool->destr2) {
+ pool->destr2(pool->destr2_data, mem->c);
+ }
+ cxFree(pool->base_allocator, mem);
size_t last_index = pool->size - 1;
if (i != last_index) {
pool->data[i] = pool->data[last_index];
@@ -137,19 +274,207 @@
abort(); // LCOV_EXCL_LINE
}
+static void *cx_mempool_realloc_advanced(
+ void *p,
+ void *ptr,
+ size_t n
+) {
+ if (ptr == NULL) {
+ return cx_mempool_malloc_advanced(p, n);
+ }
+ if (n == 0) {
+ cx_mempool_free_advanced(p, ptr);
+ return NULL;
+ }
+ struct cx_mempool_s *pool = p;
+
+ const unsigned overhead = sizeof(struct cx_mempool_memory2_s);
+ struct cx_mempool_memory2_s *mem =
+ (void *) (((char *) ptr) - overhead);
+ struct cx_mempool_memory2_s *newm =
+ cxRealloc(pool->base_allocator, mem, n + overhead);
+
+ if (newm == NULL) return NULL;
+ if (mem != newm) {
+ for (size_t i = 0; i < pool->size; i++) {
+ if (pool->data[i] == mem) {
+ pool->data[i] = newm;
+ return ((char*)newm) + overhead;
+ }
+ }
+ abort(); // LCOV_EXCL_LINE
+ } else {
+ // unfortunately glibc() realloc seems to always move
+ return ptr; // LCOV_EXCL_LINE
+ }
+}
+
+static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) {
+ const bool has_destr = pool->destr;
+ const bool has_destr2 = pool->destr2;
+ for (size_t i = 0; i < pool->size; i++) {
+ struct cx_mempool_memory2_s *mem = pool->data[i];
+ if (mem->destructor) {
+ mem->destructor(mem->data, mem->c);
+ }
+ if (has_destr) {
+ pool->destr(mem->c);
+ }
+ if (has_destr2) {
+ pool->destr2(pool->destr2_data, mem->c);
+ }
+ cxFree(pool->base_allocator, mem);
+ }
+}
+
+static cx_allocator_class cx_mempool_advanced_allocator_class = {
+ cx_mempool_malloc_advanced,
+ cx_mempool_realloc_advanced,
+ cx_mempool_calloc_advanced,
+ cx_mempool_free_advanced
+};
+
+
+static void *cx_mempool_malloc_pure(
+ void *p,
+ size_t n
+) {
+ struct cx_mempool_s *pool = p;
+
+ if (cx_mempool_ensure_capacity(pool, pool->size + 1)) {
+ return NULL; // LCOV_EXCL_LINE
+ }
+
+ void *mem = cxMalloc(pool->base_allocator, n);
+ if (mem == NULL) return NULL;
+ pool->data[pool->size] = mem;
+ pool->size++;
+
+ return mem;
+}
+
+static void *cx_mempool_calloc_pure(
+ void *p,
+ size_t nelem,
+ size_t elsize
+) {
+ size_t msz;
+ if (cx_szmul(nelem, elsize, &msz)) {
+ errno = EOVERFLOW;
+ return NULL;
+ }
+ void *ptr = cx_mempool_malloc_pure(p, msz);
+ if (ptr == NULL) return NULL;
+ memset(ptr, 0, nelem * elsize);
+ return ptr;
+}
+
+static void cx_mempool_free_pure(
+ void *p,
+ void *ptr
+) {
+ if (!ptr) return;
+ struct cx_mempool_s *pool = p;
+
+ for (size_t i = 0; i < pool->size; i++) {
+ if (ptr == pool->data[i]) {
+ if (pool->destr) {
+ pool->destr(ptr);
+ }
+ if (pool->destr2) {
+ pool->destr2(pool->destr2_data, ptr);
+ }
+ cxFree(pool->base_allocator, ptr);
+ size_t last_index = pool->size - 1;
+ if (i != last_index) {
+ pool->data[i] = pool->data[last_index];
+ pool->data[last_index] = NULL;
+ }
+ pool->size--;
+ return;
+ }
+ }
+ abort(); // LCOV_EXCL_LINE
+}
+
+static void *cx_mempool_realloc_pure(
+ void *p,
+ void *ptr,
+ size_t n
+) {
+ if (ptr == NULL) {
+ return cx_mempool_malloc_pure(p, n);
+ }
+ if (n == 0) {
+ cx_mempool_free_pure(p, ptr);
+ return NULL;
+ }
+ struct cx_mempool_s *pool = p;
+ void *newm = cxRealloc(pool->base_allocator, ptr, n);
+ if (newm == NULL) return NULL;
+ if (ptr != newm) {
+ for (size_t i = 0; i < pool->size; i++) {
+ if (pool->data[i] == ptr) {
+ pool->data[i] = newm;
+ return newm;
+ }
+ }
+ abort(); // LCOV_EXCL_LINE
+ } else {
+ // unfortunately glibc() realloc seems to always move
+ return ptr; // LCOV_EXCL_LINE
+ }
+}
+
+static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) {
+ const bool has_destr = pool->destr;
+ const bool has_destr2 = pool->destr2;
+ for (size_t i = 0; i < pool->size; i++) {
+ void *mem = pool->data[i];
+ if (has_destr) {
+ pool->destr(mem);
+ }
+ if (has_destr2) {
+ pool->destr2(pool->destr2_data, mem);
+ }
+ cxFree(pool->base_allocator, mem);
+ }
+}
+
+static cx_allocator_class cx_mempool_pure_allocator_class = {
+ cx_mempool_malloc_pure,
+ cx_mempool_realloc_pure,
+ cx_mempool_calloc_pure,
+ cx_mempool_free_pure
+};
+
+static void cx_mempool_free_foreign(const struct cx_mempool_s *pool) {
+ for (size_t i = 0; i < pool->registered_size; i++) {
+ struct cx_mempool_foreign_memory_s info = pool->registered[i];
+ if (info.destr2_data == NULL) {
+ if (info.destr) {
+ info.destr(info.mem);
+ }
+ } else {
+ info.destr2(info.destr2_data, info.mem);
+ }
+ }
+}
+
void cxMempoolFree(CxMempool *pool) {
if (pool == NULL) return;
- struct cx_mempool_memory_s *mem;
- for (size_t i = 0; i < pool->size; i++) {
- mem = pool->data[i];
- if (mem->destructor) {
- mem->destructor(mem->c);
- }
- free(mem);
+ if (pool->allocator->cl == &cx_mempool_simple_allocator_class) {
+ cx_mempool_free_all_simple(pool);
+ } else if (pool->allocator->cl == &cx_mempool_advanced_allocator_class) {
+ cx_mempool_free_all_advanced(pool);
+ } else {
+ cx_mempool_free_all_pure(pool);
}
- free(pool->data);
- free((void*) pool->allocator);
- free(pool);
+ cx_mempool_free_foreign(pool);
+ cxFree(pool->base_allocator, pool->data);
+ cxFree(pool->base_allocator, pool->registered);
+ cxFree(pool->base_allocator, (void*) pool->allocator);
+ cxFree(pool->base_allocator, pool);
}
void cxMempoolSetDestructor(
@@ -159,18 +484,26 @@
*(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
}
+void cxMempoolSetDestructor2(
+ void *ptr,
+ cx_destructor_func2 func,
+ void *data
+) {
+ struct cx_mempool_memory2_s *info =
+ (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
+ info->destructor = func;
+ info->data = data;
+}
+
void cxMempoolRemoveDestructor(void *ptr) {
*(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = NULL;
}
-struct cx_mempool_foreign_mem_s {
- cx_destructor_func destr;
- void* mem;
-};
-
-static void cx_mempool_destr_foreign_mem(void* ptr) {
- struct cx_mempool_foreign_mem_s *fm = ptr;
- fm->destr(fm->mem);
+void cxMempoolRemoveDestructor2(void *ptr) {
+ struct cx_mempool_memory2_s *info =
+ (void*)((char *) ptr - sizeof(struct cx_mempool_memory2_s));
+ info->destructor = NULL;
+ info->data = NULL;
}
int cxMempoolRegister(
@@ -178,60 +511,206 @@
void *memory,
cx_destructor_func destr
) {
- struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc(
- pool,
- sizeof(struct cx_mempool_foreign_mem_s)
- );
- if (fm == NULL) return 1;
+ if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+
+ pool->registered[pool->registered_size++] =
+ (struct cx_mempool_foreign_memory_s) {
+ .mem = memory,
+ .destr = destr,
+ .destr2_data = NULL
+ };
+
+ return 0;
+}
- fm->mem = memory;
- fm->destr = destr;
- *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem;
+int cxMempoolRegister2(
+ CxMempool *pool,
+ void *memory,
+ cx_destructor_func2 destr,
+ void *data
+) {
+ if (cx_mempool_ensure_registered_capacity(pool, pool->registered_size + 1)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+
+ pool->registered[pool->registered_size++] =
+ (struct cx_mempool_foreign_memory_s) {
+ .mem = memory,
+ .destr2 = destr,
+ .destr2_data = data
+ };
return 0;
}
-static cx_allocator_class cx_mempool_allocator_class = {
- cx_mempool_malloc,
- cx_mempool_realloc,
- cx_mempool_calloc,
- cx_mempool_free
-};
-
CxMempool *cxMempoolCreate(
size_t capacity,
- cx_destructor_func destr
+ enum cx_mempool_type type
) {
+ if (capacity == 0) capacity = 16;
size_t poolsize;
- if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) {
+ if (cx_szmul(capacity, sizeof(void*), &poolsize)) {
+ // LCOV_EXCL_START
errno = EOVERFLOW;
return NULL;
+ } // LCOV_EXCL_STOP
+
+ CxAllocator *provided_allocator = cxMallocDefault(sizeof(CxAllocator));
+ if (provided_allocator == NULL) { // LCOV_EXCL_START
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ CxMempool *pool = cxCallocDefault(1, sizeof(CxMempool));
+ if (pool == NULL) { // LCOV_EXCL_START
+ cxFreeDefault(provided_allocator);
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ provided_allocator->data = pool;
+ *((const CxAllocator**)&pool->base_allocator) = cxDefaultAllocator;
+ pool->allocator = provided_allocator;
+ if (type == CX_MEMPOOL_TYPE_SIMPLE) {
+ provided_allocator->cl = &cx_mempool_simple_allocator_class;
+ } else if (type == CX_MEMPOOL_TYPE_ADVANCED) {
+ provided_allocator->cl = &cx_mempool_advanced_allocator_class;
+ } else {
+ provided_allocator->cl = &cx_mempool_pure_allocator_class;
}
- struct cx_mempool_s *pool =
- malloc(sizeof(struct cx_mempool_s));
- if (pool == NULL) return NULL;
-
- CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
- if (provided_allocator == NULL) { // LCOV_EXCL_START
- free(pool);
- return NULL;
- } // LCOV_EXCL_STOP
- provided_allocator->cl = &cx_mempool_allocator_class;
- provided_allocator->data = pool;
-
- pool->allocator = provided_allocator;
-
- pool->data = malloc(poolsize);
+ pool->data = cxMallocDefault(poolsize);
if (pool->data == NULL) { // LCOV_EXCL_START
- free(provided_allocator);
- free(pool);
+ cxFreeDefault(provided_allocator);
+ cxFreeDefault(pool);
return NULL;
} // LCOV_EXCL_STOP
pool->size = 0;
pool->capacity = capacity;
- pool->auto_destr = destr;
return pool;
}
+
+void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc) {
+ pool->destr = fnc;
+}
+
+void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data) {
+ pool->destr2 = fnc;
+ pool->destr2_data = data;
+}
+
+static void cx_mempool_free_transferred_allocator(void *base_al, void *al) {
+ cxFree(base_al, al);
+}
+
+int cxMempoolTransfer(
+ CxMempool *source,
+ CxMempool *dest
+) {
+ // safety checks
+ if (source == dest) return 1;
+ if (source->allocator->cl != dest->allocator->cl) return 1;
+ if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
+
+ // ensure enough capacity in the destination pool
+ if (cx_mempool_ensure_capacity(dest, dest->size + source->size)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+ if (cx_mempool_ensure_registered_capacity(dest,
+ dest->registered_size + source->registered_size)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+
+ // allocate a replacement allocator for the source pool
+ CxAllocator *new_source_allocator =
+ cxMalloc(source->base_allocator, sizeof(CxAllocator));
+ if (new_source_allocator == NULL) { // LCOV_EXCL_START
+ return 1;
+ } // LCOV_EXCL_STOP
+ new_source_allocator->cl = source->allocator->cl;
+ new_source_allocator->data = source;
+
+ // transfer all the data
+ memcpy(&dest->data[dest->size], source->data, sizeof(void*)*source->size);
+ dest->size += source->size;
+
+ // transfer all registered memory
+ memcpy(&dest->registered[dest->registered_size], source->registered,
+ sizeof(struct cx_mempool_foreign_memory_s) * source->registered_size);
+ dest->registered_size += source->registered_size;
+
+ // register the old allocator with the new pool
+ // we have to remove const-ness for this, but that's okay here
+ // also register the base allocator, s.t. the pool knows how to free it
+ CxAllocator *transferred_allocator = (CxAllocator*) source->allocator;
+ transferred_allocator->data = dest;
+ cxMempoolRegister2(dest, transferred_allocator,
+ cx_mempool_free_transferred_allocator, (void*)source->base_allocator);
+
+ // prepare the source pool for re-use
+ source->allocator = new_source_allocator;
+ memset(source->data, 0, source->size * sizeof(void*));
+ memset(source->registered, 0,
+ source->registered_size * sizeof(struct cx_mempool_foreign_memory_s));
+ source->size = 0;
+ source->registered_size = 0;
+
+ return 0;
+}
+
+int cxMempoolTransferObject(
+ CxMempool *source,
+ CxMempool *dest,
+ const void *obj
+) {
+ // safety checks
+ if (source == dest) return 1;
+ if (source->allocator->cl != dest->allocator->cl) return 1;
+ if (source->base_allocator->cl != dest->base_allocator->cl) return 1;
+
+ // search for the object
+ for (size_t i = 0; i < source->size; i++) {
+ struct cx_mempool_memory_s *mem = source->data[i];
+ if (mem->c == obj) {
+ // first, make sure that the dest pool can take the object
+ if (cx_mempool_ensure_capacity(dest, dest->size + 1)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+ // remove from the source pool
+ size_t last_index = source->size - 1;
+ if (i != last_index) {
+ source->data[i] = source->data[last_index];
+ source->data[last_index] = NULL;
+ }
+ source->size--;
+ // add to the target pool
+ dest->data[dest->size++] = mem;
+ return 0;
+ }
+ }
+ // search in the registered objects
+ for (size_t i = 0; i < source->registered_size; i++) {
+ struct cx_mempool_foreign_memory_s *mem = &source->registered[i];
+ if (mem->mem == obj) {
+ // first, make sure that the dest pool can take the object
+ if (cx_mempool_ensure_registered_capacity(dest,
+ dest->registered_size + 1)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+ dest->registered[dest->registered_size++] = *mem;
+ // remove from the source pool
+ size_t last_index = source->registered_size - 1;
+ if (i != last_index) {
+ source->registered[i] = source->registered[last_index];
+ memset(&source->registered[last_index], 0,
+ sizeof(struct cx_mempool_foreign_memory_s));
+ }
+ source->registered_size--;
+ return 0;
+ }
+ }
+ // not found
+ return 1;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ucx/printf.c
--- a/ucx/printf.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/printf.c Sun Jul 20 22:04:39 2025 +0200
@@ -68,7 +68,7 @@
return (int) wfc(buf, 1, ret, stream);
} else {
int len = ret + 1;
- char *newbuf = malloc(len);
+ char *newbuf = cxMallocDefault(len);
if (!newbuf) { // LCOV_EXCL_START
va_end(ap2);
return -1;
@@ -79,7 +79,7 @@
if (ret > 0) {
ret = (int) wfc(newbuf, 1, ret, stream);
}
- free(newbuf);
+ cxFreeDefault(newbuf);
}
return ret;
}
@@ -121,7 +121,7 @@
if (s.ptr) {
ret = vsnprintf(s.ptr, len, fmt, ap2);
if (ret < 0) {
- free(s.ptr);
+ cxFree(a, s.ptr);
s.ptr = NULL;
} else {
s.length = (size_t) ret;
@@ -132,7 +132,13 @@
return s;
}
-int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) {
+int cx_sprintf_a(
+ const CxAllocator *alloc,
+ char **str,
+ size_t *len,
+ const char *fmt,
+ ...
+) {
va_list ap;
va_start(ap, fmt);
int ret = cx_vsprintf_a(alloc, str, len, fmt, ap);
@@ -140,7 +146,13 @@
return ret;
}
-int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) {
+int cx_vsprintf_a(
+ const CxAllocator *alloc,
+ char **str,
+ size_t *len,
+ const char *fmt,
+ va_list ap
+) {
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(*str, *len, fmt, ap);
@@ -162,7 +174,14 @@
return ret;
}
-int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) {
+int cx_sprintf_sa(
+ const CxAllocator *alloc,
+ char *buf,
+ size_t *len,
+ char **str,
+ const char *fmt,
+ ...
+) {
va_list ap;
va_start(ap, fmt);
int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap);
@@ -170,7 +189,14 @@
return ret;
}
-int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) {
+int cx_vsprintf_sa(
+ const CxAllocator *alloc,
+ char *buf,
+ size_t *len,
+ char **str,
+ const char *fmt,
+ va_list ap
+) {
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(buf, *len, fmt, ap);
diff -r b34bd1557c6c -r 77254bd6dccb ucx/properties.c
--- a/ucx/properties.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/properties.c Sun Jul 20 22:04:39 2025 +0200
@@ -287,7 +287,7 @@
cx_attr_unused CxProperties *prop,
CxPropertiesSource *src
) {
- src->data_ptr = malloc(src->data_size);
+ src->data_ptr = cxMallocDefault(src->data_size);
if (src->data_ptr == NULL) return 1;
return 0;
}
@@ -296,7 +296,7 @@
cx_attr_unused CxProperties *prop,
CxPropertiesSource *src
) {
- free(src->data_ptr);
+ cxFreeDefault(src->data_ptr);
}
CxPropertiesSource cxPropertiesStringSource(cxstring str) {
diff -r b34bd1557c6c -r 77254bd6dccb ucx/streams.c
--- a/ucx/streams.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/streams.c Sun Jul 20 22:04:39 2025 +0200
@@ -27,6 +27,7 @@
*/
#include "cx/streams.h"
+#include "cx/allocator.h"
#ifndef CX_STREAM_BCOPY_BUF_SIZE
#define CX_STREAM_BCOPY_BUF_SIZE 8192
@@ -57,7 +58,7 @@
lbuf = buf;
} else {
if (bufsize == 0) bufsize = CX_STREAM_BCOPY_BUF_SIZE;
- lbuf = malloc(bufsize);
+ lbuf = cxMallocDefault(bufsize);
if (lbuf == NULL) return 0;
}
@@ -74,7 +75,7 @@
}
if (lbuf != buf) {
- free(lbuf);
+ cxFreeDefault(lbuf);
}
return ncp;
diff -r b34bd1557c6c -r 77254bd6dccb ucx/string.c
--- a/ucx/string.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/string.c Sun Jul 20 22:04:39 2025 +0200
@@ -65,7 +65,7 @@
void cx_strfree(cxmutstr *str) {
if (str == NULL) return;
- free(str->ptr);
+ cxFreeDefault(str->ptr);
str->ptr = NULL;
str->length = 0;
}
@@ -80,6 +80,22 @@
str->length = 0;
}
+int cx_strcpy_a(
+ const CxAllocator *alloc,
+ cxmutstr *dest,
+ cxstring src
+) {
+ if (cxReallocate(alloc, &dest->ptr, src.length + 1)) {
+ return 1;
+ }
+
+ memcpy(dest->ptr, src.ptr, src.length);
+ dest->length = src.length;
+ dest->ptr[dest->length] = '\0';
+
+ return 0;
+}
+
size_t cx_strlen(
size_t count,
...
@@ -106,27 +122,16 @@
...
) {
if (count == 0) return str;
-
- cxstring strings_stack[8];
- cxstring *strings;
- if (count > 8) {
- strings = calloc(count, sizeof(cxstring));
- if (strings == NULL) {
- return (cxmutstr) {NULL, 0};
- }
- } else {
- strings = strings_stack;
- }
-
va_list ap;
va_start(ap, count);
+ va_list ap2;
+ va_copy(ap2, ap);
- // get all args and overall length
+ // compute overall length
bool overflow = false;
size_t slen = str.length;
for (size_t i = 0; i < count; i++) {
- cxstring s = va_arg (ap, cxstring);
- strings[i] = s;
+ cxstring s = va_arg(ap, cxstring);
if (slen > SIZE_MAX - str.length) overflow = true;
slen += s.length;
}
@@ -134,10 +139,8 @@
// abort in case of overflow
if (overflow) {
+ va_end(ap2);
errno = EOVERFLOW;
- if (strings != strings_stack) {
- free(strings);
- }
return (cxmutstr) { NULL, 0 };
}
@@ -149,9 +152,7 @@
newstr = cxRealloc(alloc, str.ptr, slen + 1);
}
if (newstr == NULL) {
- if (strings != strings_stack) {
- free(strings);
- }
+ va_end(ap2);
return (cxmutstr) {NULL, 0};
}
str.ptr = newstr;
@@ -160,19 +161,15 @@
size_t pos = str.length;
str.length = slen;
for (size_t i = 0; i < count; i++) {
- cxstring s = strings[i];
+ cxstring s = va_arg(ap2, cxstring);
memcpy(str.ptr + pos, s.ptr, s.length);
pos += s.length;
}
+ va_end(ap2);
// terminate string
str.ptr[str.length] = '\0';
- // free temporary array
- if (strings != strings_stack) {
- free(strings);
- }
-
return str;
}
@@ -289,8 +286,9 @@
// check needle length and use appropriate prefix table
// if the pattern exceeds static prefix table, allocate on the heap
const bool useheap = needle.length >= CX_STRSTR_SBO_SIZE;
- register size_t *ptable = useheap ? calloc(needle.length + 1,
- sizeof(size_t)) : s_prefix_table;
+ register size_t *ptable = useheap
+ ? cxCallocDefault(needle.length + 1, sizeof(size_t))
+ : s_prefix_table;
// keep counter in registers
register size_t i, j;
@@ -328,7 +326,7 @@
// if prefix table was allocated on the heap, free it
if (useheap) {
- free(ptable);
+ cxFreeDefault(ptable);
}
return result;
@@ -588,27 +586,6 @@
#endif
}
-#ifndef CX_STRREPLACE_INDEX_BUFFER_SIZE
-#define CX_STRREPLACE_INDEX_BUFFER_SIZE 64
-#endif
-
-struct cx_strreplace_ibuf {
- size_t *buf;
- struct cx_strreplace_ibuf *next;
- unsigned int len;
-};
-
-static void cx_strrepl_free_ibuf(struct cx_strreplace_ibuf *buf) {
- // remember, the first data is on the stack!
- buf = buf->next;
- while (buf) {
- struct cx_strreplace_ibuf *next = buf->next;
- free(buf->buf);
- free(buf);
- buf = next;
- }
-}
-
cxmutstr cx_strreplacen_a(
const CxAllocator *allocator,
cxstring str,
@@ -616,108 +593,60 @@
cxstring replacement,
size_t replmax
) {
+ // special cases
+ if (search.length == 0 || search.length > str.length || replmax == 0) {
+ return cx_strdup_a(allocator, str);
+ }
- if (search.length == 0 || search.length > str.length || replmax == 0)
- return cx_strdup_a(allocator, str);
+ size_t in_len = str.length;
+ size_t search_len = search.length;
+ size_t repl_len = replacement.length;
- // Compute expected buffer length
- size_t ibufmax = str.length / search.length;
- size_t ibuflen = replmax < ibufmax ? replmax : ibufmax;
- if (ibuflen > CX_STRREPLACE_INDEX_BUFFER_SIZE) {
- ibuflen = CX_STRREPLACE_INDEX_BUFFER_SIZE;
+ // first run, count the occurrences
+ // and remember where the first is
+ size_t occurrences = 1;
+ cxstring first = cx_strstr(str, search);
+ if (first.length == 0) {
+ // special case, no replacements
+ return cx_strdup_a(allocator, str);
+ }
+ cxstring tmp = cx_strsubs(first, search_len);
+ while (occurrences < replmax &&
+ (tmp = cx_strstr(tmp, search)).length > 0) {
+ occurrences++;
+ tmp = cx_strsubs(tmp, search_len);
}
- // First index buffer can be on the stack
- struct cx_strreplace_ibuf ibuf, *curbuf = &ibuf;
- size_t ibuf_sbo[CX_STRREPLACE_INDEX_BUFFER_SIZE];
- ibuf.buf = ibuf_sbo;
- ibuf.next = NULL;
- ibuf.len = 0;
+ // calculate necessary memory
+ signed long long diff_len = (signed long long) repl_len - search_len;
+ size_t out_len = in_len + diff_len * occurrences;
+ cxmutstr out = {
+ cxMalloc(allocator, out_len + 1),
+ out_len
+ };
+ if (out.ptr == NULL) return out;
- // Search occurrences
- cxstring searchstr = str;
- size_t found = 0;
- do {
- cxstring match = cx_strstr(searchstr, search);
- if (match.length > 0) {
- // Allocate next buffer in chain, if required
- if (curbuf->len == ibuflen) {
- struct cx_strreplace_ibuf *nextbuf =
- calloc(1, sizeof(struct cx_strreplace_ibuf));
- if (!nextbuf) {
- cx_strrepl_free_ibuf(&ibuf);
- return cx_mutstrn(NULL, 0);
- }
- nextbuf->buf = calloc(ibuflen, sizeof(size_t));
- if (!nextbuf->buf) {
- free(nextbuf);
- cx_strrepl_free_ibuf(&ibuf);
- return cx_mutstrn(NULL, 0);
- }
- curbuf->next = nextbuf;
- curbuf = nextbuf;
- }
-
- // Record match index
- found++;
- size_t idx = match.ptr - str.ptr;
- curbuf->buf[curbuf->len++] = idx;
- searchstr.ptr = match.ptr + search.length;
- searchstr.length = str.length - idx - search.length;
- } else {
- break;
- }
- } while (searchstr.length > 0 && found < replmax);
-
- // Allocate result string
- cxmutstr result;
- {
- long long adjlen = (long long) replacement.length - (long long) search.length;
- size_t rcount = 0;
- curbuf = &ibuf;
- do {
- rcount += curbuf->len;
- curbuf = curbuf->next;
- } while (curbuf);
- result.length = str.length + rcount * adjlen;
- result.ptr = cxMalloc(allocator, result.length + 1);
- if (!result.ptr) {
- cx_strrepl_free_ibuf(&ibuf);
- return cx_mutstrn(NULL, 0);
- }
+ // second run: perform the replacements
+ // but start where we found the first occurrence
+ const char *inp = str.ptr;
+ tmp = first;
+ char *outp = out.ptr;
+ while (occurrences-- > 0 && (tmp = cx_strstr(tmp, search)).length > 0) {
+ size_t copylen = tmp.ptr - inp;
+ memcpy(outp, inp, copylen);
+ outp += copylen;
+ memcpy(outp, replacement.ptr, repl_len);
+ outp += repl_len;
+ inp += copylen + search_len;
+ tmp = cx_strsubs(tmp, search_len);
}
- // Build result string
- curbuf = &ibuf;
- size_t srcidx = 0;
- char *destptr = result.ptr;
- do {
- for (size_t i = 0; i < curbuf->len; i++) {
- // Copy source part up to next match
- size_t idx = curbuf->buf[i];
- size_t srclen = idx - srcidx;
- if (srclen > 0) {
- memcpy(destptr, str.ptr + srcidx, srclen);
- destptr += srclen;
- srcidx += srclen;
- }
+ // add the remaining string
+ size_t copylen = in_len - (inp - str.ptr);
+ memcpy(outp, inp, copylen);
+ out.ptr[out_len] = '\0';
- // Copy the replacement and skip the source pattern
- srcidx += search.length;
- memcpy(destptr, replacement.ptr, replacement.length);
- destptr += replacement.length;
- }
- curbuf = curbuf->next;
- } while (curbuf);
- memcpy(destptr, str.ptr + srcidx, str.length - srcidx);
-
- // Result is guaranteed to be zero-terminated
- result.ptr[result.length] = '\0';
-
- // Free index buffer
- cx_strrepl_free_ibuf(&ibuf);
-
- return result;
+ return out;
}
CxStrtokCtx cx_strtok_(
diff -r b34bd1557c6c -r 77254bd6dccb ucx/tree.c
--- a/ucx/tree.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ucx/tree.c Sun Jul 20 22:04:39 2025 +0200
@@ -226,14 +226,14 @@
int ret_elem = sfunc(elem, node);
if (ret_elem == 0) {
// if found, exit the search
- *result = (void *) elem;
+ *result = elem;
ret = 0;
break;
} else if (ret_elem > 0 && ret_elem < ret) {
// new distance is better
*result = elem;
ret = ret_elem;
- } else {
+ } else if (ret_elem < 0 || ret_elem > ret) {
// not contained or distance is worse, skip entire subtree
cxTreeIteratorContinue(iter);
}
@@ -305,12 +305,12 @@
if (children == NULL) {
// search for the next node
- void *next;
+ void *next = NULL;
cx_tree_iter_search_next:
- // check if there is a sibling
+ // check if there is a sibling, but only if we are not a (subtree-)root
if (iter->exiting) {
next = iter->node_next;
- } else {
+ } else if (iter->depth > 1) {
next = tree_next(iter->node);
iter->node_next = next;
}
@@ -326,7 +326,7 @@
// invalidate the iterator and free the node stack
iter->node = iter->node_next = NULL;
iter->stack_capacity = iter->depth = 0;
- free(iter->stack);
+ cxFreeDefault(iter->stack);
iter->stack = NULL;
} else {
// the parent node can be obtained from the top of stack
@@ -386,7 +386,7 @@
iter.node = root;
if (root != NULL) {
iter.stack_capacity = 16;
- iter.stack = malloc(sizeof(void *) * 16);
+ iter.stack = cxMallocDefault(sizeof(void *) * 16);
iter.stack[0] = root;
iter.counter = 1;
iter.depth = 1;
@@ -416,7 +416,7 @@
node = tree_next(node);
while (node != NULL) {
struct cx_tree_visitor_queue_s *q;
- q = malloc(sizeof(struct cx_tree_visitor_queue_s));
+ q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s));
q->depth = iter->queue_last->depth;
q->node = node;
iter->queue_last->next = q;
@@ -445,7 +445,7 @@
}
if (children != NULL) {
struct cx_tree_visitor_queue_s *q;
- q = malloc(sizeof(struct cx_tree_visitor_queue_s));
+ q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s));
q->depth = iter->depth + 1;
q->node = children;
if (iter->queue_last == NULL) {
@@ -474,7 +474,7 @@
assert(iter->queue_last == q);
iter->queue_last = NULL;
}
- free(q);
+ cxFreeDefault(q);
}
// increment the node counter
diff -r b34bd1557c6c -r 77254bd6dccb ui/Makefile
--- a/ui/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -33,15 +33,16 @@
include common/objs.mk
-UI_LIB = ../build/lib/$(LIB_PREFIX)uitk$(LIB_EXT)
+UI_LIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
+UI_SHLIB = ../build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(SHLIB_EXT)
include $(TOOLKIT)/objs.mk
OBJ = $(TOOLKITOBJS) $(COMMONOBJS)
-all: $(UI_LIB)
+all: $(UI_LIB) $(UI_SHLIB)
include $(TOOLKIT)/Makefile
$(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c
- $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(TK_CFLAGS) $<
+ $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/EventData.h
--- a/ui/cocoa/EventData.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/EventData.h Sun Jul 20 22:04:39 2025 +0200
@@ -47,6 +47,5 @@
- (void)handleEventWithEventData:(id)sender;
-- (SEL)addDynamicMethod:(unsigned long long)method_id;
+@end
-@end
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/MainWindow.h
--- a/ui/cocoa/MainWindow.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/MainWindow.h Sun Jul 20 22:04:39 2025 +0200
@@ -31,8 +31,36 @@
@interface MainWindow : NSWindow
-@property UiObject *uiobj;
-
- (MainWindow*)init:(UiObject*)obj;
@end
+
+
+@interface MainWindowController : NSWindowController
+
+@property UiObject *uiobj;
+@property NSMutableDictionary *checkItemStates;
+@property NSMutableDictionary *radioItems;
+
+- (MainWindowController*)initWithWindow:(UiObject*)obj window:(NSWindow*)window;
+
+- (void) windowDidLoad;
+
+- (void)menuItemAction:(id)sender;
+
+- (BOOL) validateMenuItem:(NSMenuItem *) menuItem;
+
+@end
+
+@interface MenuItemState : NSObject
+@property (weak) MainWindowController *mainWindow;
+@property UiVar *var;
+@property int state;
+@end
+
+
+int64_t ui_menu_check_item_get(UiInteger *i);
+void ui_menu_check_item_set(UiInteger *i, int64_t value);
+
+int64_t ui_menu_radio_item_get(UiInteger *i);
+void ui_menu_radio_item_set(UiInteger *i, int64_t value);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/MainWindow.m
--- a/ui/cocoa/MainWindow.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/MainWindow.m Sun Jul 20 22:04:39 2025 +0200
@@ -30,11 +30,14 @@
#import "Container.h"
#import "GridLayout.h"
#import "../common/object.h"
+#import
+
+#import "EventData.h"
+#import "menu.h"
@implementation MainWindow
- (MainWindow*)init:(UiObject*)obj {
- self.uiobj = obj;
NSRect frame = NSMakeRect(300, 200, 600, 500);
self = [self initWithContentRect:frame
@@ -63,3 +66,198 @@
}
@end
+
+
+
+@implementation MainWindowController
+
+- (MainWindowController*)initWithWindow:(UiObject*)obj window:(NSWindow*)window {
+ self = [super initWithWindow:window];
+ _uiobj = obj;
+
+ self.checkItemStates = [[NSMutableDictionary alloc] init];
+ self.radioItems = [[NSMutableDictionary alloc] init];
+
+ // bind all stateful menu items (checkbox, radiobuttons, lists)
+ NSArray *menuBindItems = ui_get_binding_items(); // returns all items that require binding
+ for(MenuItem *item in menuBindItems) {
+ if(item.checkItem || item.radioItem) {
+ // simple check item (ui_menu_toggleitem_create)
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, item.checkItem ? item.checkItem->varname : item.radioItem->varname, UI_VAR_INTEGER);
+ // create the state object for this item/window
+ MenuItemState *state = [[MenuItemState alloc] init];
+ state.mainWindow = self;
+ state.var = var;
+ if(var) {
+ UiInteger *i = var->value;
+ if(item.checkItem) {
+ // bind toggle item
+ state.state = (int)i->value;
+ i->obj = (__bridge void*)state;
+ i->get = ui_menu_check_item_get;
+ i->set = ui_menu_check_item_set;
+ } else {
+ // bind radio item
+ NSMutableArray *rgroup = nil;
+ if(i->obj) {
+ rgroup = (__bridge NSMutableArray*)i->obj;
+ } else {
+ // create a new rgroup array and register it in the window
+ rgroup = [[NSMutableArray alloc] init];
+ NSString *varname = [[NSString alloc] initWithUTF8String:item.radioItem->varname];
+ [_radioItems setObject:rgroup forKey:varname];
+ i->obj = (__bridge void*)rgroup;
+ }
+ i->get = ui_menu_radio_item_get;
+ i->set = ui_menu_radio_item_set;
+ [rgroup addObject:state]; // add this item state to the radio group
+ // i->value can contain a non-zero value, which means a specific radiobutton
+ // should be pre-selected
+ if(i->value == rgroup.count) {
+ state.state = NSControlStateValueOn;
+ }
+ }
+ } else {
+ state.state = 0;
+ }
+ [_checkItemStates setObject:state forKey:item.itemId];
+ }
+ }
+
+ return self;
+}
+
+- (void) windowDidLoad {
+ [self.window setNextResponder:self];
+}
+
+- (void)menuItemAction:(id)sender {
+ EventData *event = objc_getAssociatedObject(sender, "eventdata");
+ if(event) {
+ event.obj = self.uiobj; // temporary set the event object
+ [event handleEvent:sender];
+ }
+}
+
+- (void)menuCheckItemAction:(id)sender {
+ NSMenuItem *menuItem = sender;
+ MenuItem *item = objc_getAssociatedObject(sender, "menuitem");
+ if(!item || !item.checkItem) {
+ return;
+ }
+
+ MenuItemState *state = [_checkItemStates objectForKey:item.itemId];
+ state.state = state.state == NSControlStateValueOff ? NSControlStateValueOn : NSControlStateValueOff;
+ menuItem.state = state.state;
+
+ UiMenuCheckItem *it = item.checkItem;
+ if(it->callback) {
+ UiEvent event;
+ event.obj = _uiobj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = state.var ? state.var->value : NULL;
+ event.intval = state.state;
+ it->callback(&event, it->userdata);
+ }
+}
+
+- (void)menuRadioItemAction:(id)sender {
+ NSMenuItem *menuItem = sender;
+ MenuItem *item = objc_getAssociatedObject(sender, "menuitem");
+ if(!item || !item.radioItem) {
+ return;
+ }
+
+ UiMenuRadioItem *it = item.radioItem;
+ if(!it->varname) {
+ return;
+ }
+
+ MenuItemState *state = [_checkItemStates objectForKey:item.itemId]; // current state of this menu item
+
+ NSString *varname = [[NSString alloc] initWithUTF8String:it->varname];
+ NSArray *radioGroup = [_radioItems objectForKey:varname];
+ if(!radioGroup) {
+ return;
+ }
+ int index = 1;
+ int value = 0;
+ for(MenuItemState *g in radioGroup) {
+ if(g == state) {
+ menuItem.state = NSControlStateValueOn;
+ g.state = NSControlStateValueOn;
+ value = index;
+ } else {
+ menuItem.state = NSControlStateValueOff;
+ g.state = NSControlStateValueOff;
+ }
+ }
+
+ if(it->callback) {
+ UiEvent event;
+ event.obj = _uiobj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = state.var ? state.var->value : NULL;
+ event.intval = value;
+ it->callback(&event, it->userdata);
+ }
+}
+
+
+- (BOOL) validateMenuItem:(NSMenuItem *) menuItem {
+ MenuItem *item = objc_getAssociatedObject(menuItem, "menuitem");
+ if(item) {
+ MenuItemState *state = [_checkItemStates objectForKey:item.itemId];
+ if(state) {
+ menuItem.state = state.state;
+ } else {
+ menuItem.state = NSControlStateValueOff;
+ }
+ }
+
+ return YES;
+}
+
+@end
+
+@implementation MenuItemState
+
+@end
+
+int64_t ui_menu_check_item_get(UiInteger *i) {
+ MenuItemState *state = (__bridge MenuItemState*)i->obj;
+ i->value = state.state;
+ return i->value;
+}
+
+void ui_menu_check_item_set(UiInteger *i, int64_t value) {
+ MenuItemState *state = (__bridge MenuItemState*)i->obj;
+ i->value = value;
+ state.state = (int)value;
+}
+
+int64_t ui_menu_radio_item_get(UiInteger *i) {
+ NSArray *rgroup = (__bridge NSArray*)i->obj;
+ i->value = 0;
+ int index = 1;
+ for(MenuItemState *state in rgroup) {
+ if(state.state == NSControlStateValueOn) {
+ i->value = index;
+ break;
+ }
+ index++;
+ }
+ return i->value;
+}
+
+void ui_menu_radio_item_set(UiInteger *i, int64_t value) {
+ NSArray *rgroup = (__bridge NSArray*)i->obj;
+ i->value = 0;
+ int index = 1;
+ for(MenuItemState *state in rgroup) {
+ state.state = value == index;
+ index++;
+ }
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/Makefile
--- a/ui/cocoa/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -27,8 +27,10 @@
#
$(COCOA_OBJPRE)%.o: cocoa/%.m
- $(CC) -o $@ -c -I../ucx -fobjc-arc $(CFLAGS) $(TK_CFLAGS) $<
+ $(CC) -o $@ -c -I../ucx -fobjc-arc $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
$(UI_LIB): $(OBJ)
$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
+$(UI_SHLIB): $(OBJ)
+ $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/button.h
--- a/ui/cocoa/button.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/button.h Sun Jul 20 22:04:39 2025 +0200
@@ -30,6 +30,17 @@
#import "../ui/button.h"
+@interface UiRadioButton : NSButton
+
+@property UiVar *var;
+@property Boolean direct_state;
+
+- (UiRadioButton*)init;
+- (void)setState:(NSControlStateValue)state;
+
+@end
+
+
int64_t ui_togglebutton_get(UiInteger *i);
void ui_togglebutton_set(UiInteger *i, int64_t value);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/button.m
--- a/ui/cocoa/button.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/button.m Sun Jul 20 22:04:39 2025 +0200
@@ -31,15 +31,15 @@
#import "Container.h"
#import
-UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) {
+UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
NSButton *button = [[NSButton alloc] init];
- if(args.label) {
- NSString *label = [[NSString alloc] initWithUTF8String:args.label];
+ if(args->label) {
+ NSString *label = [[NSString alloc] initWithUTF8String:args->label];
button.title = label;
}
- if(args.onclick) {
- EventData *event = [[EventData alloc] init:args.onclick userdata:args.onclickdata];
+ if(args->onclick) {
+ EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
event.obj = obj;
button.target = event;
button.action = @selector(handleEvent:);
@@ -59,17 +59,17 @@
*value = (int)state;
}
-UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs args, enum NSButtonType type) {
+UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs *args, enum NSButtonType type) {
NSButton *button = [[NSButton alloc] init];
[button setButtonType:type];
//[button setAllowsMixedState:YES];
- if(args.label) {
- NSString *label = [[NSString alloc] initWithUTF8String:args.label];
+ if(args->label) {
+ NSString *label = [[NSString alloc] initWithUTF8String:args->label];
button.title = label;
}
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *i = var->value;
i->obj = (__bridge void*)button;
@@ -77,8 +77,8 @@
i->set = ui_togglebutton_set;
}
- if(args.onchange) {
- EventData *event = [[EventData alloc] init:args.onchange userdata:args.onchangedata];
+ if(args->onchange) {
+ EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata];
event.get_eventdata = togglebutton_eventdata;
event.obj = obj;
event.var = var;
@@ -113,11 +113,11 @@
button.state = state;
}
-UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) {
return togglebutton_create(obj, args, NSButtonTypePushOnPushOff);
}
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
return togglebutton_create(obj, args, NSButtonTypeSwitch);
}
@@ -127,10 +127,10 @@
*value = (int)state;
}
-UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
NSSwitch *button = [[NSSwitch alloc] init];
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *i = var->value;
i->obj = (__bridge void*)button;
@@ -138,8 +138,8 @@
i->set = ui_switch_set;
}
- if(args.onchange) {
- EventData *event = [[EventData alloc] init:args.onchange userdata:args.onchangedata];
+ if(args->onchange) {
+ EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata];
event.get_eventdata = switch_eventdata;
event.obj = obj;
event.var = var;
@@ -174,17 +174,45 @@
button.state = state;
}
+
+@implementation UiRadioButton
+
+- (UiRadioButton*)init {
+ self = [super init];
+ _direct_state = NO;
+ [self setButtonType:NSButtonTypeRadio];
+ return self;
+}
+
+- (void)setState:(NSControlStateValue)state {
+ // NOOP
+}
+
+@end
+
static void radiobutton_eventdata(id button, UiVar *var, void **eventdata, int *value) {
if(var) {
- printf("switch radiobutton\n");
+ UiInteger *value = var->value;
+ NSMutableArray *buttons = (__bridge NSMutableArray*)value->obj;
+ for(UiRadioButton *b in buttons) {
+ if(b != button) {
+ b.direct_state = YES;
+ [[b cell] setState:0];
+ b.direct_state = NO;
+ }
+ }
}
}
-UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) {
- NSButton *button = [[NSButton alloc] init];
- [button setButtonType:NSButtonTypeRadio];
+UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) {
+ UiRadioButton *button = [[UiRadioButton alloc] init];
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ if(args->label) {
+ button.title = [[NSString alloc] initWithUTF8String:args->label];
+ }
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ button.var = var;
NSMutableArray *buttons = nil;
if(var) {
UiInteger *i = var->value;
@@ -199,8 +227,8 @@
objc_setAssociatedObject(button, "radiogroup", buttons, OBJC_ASSOCIATION_RETAIN);
}
- if(args.onchange || var) {
- EventData *event = [[EventData alloc] init:args.onchange userdata:args.onchangedata];
+ if(args->onchange || var) {
+ EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata];
event.get_eventdata = radiobutton_eventdata;
event.obj = obj;
event.var = var;
@@ -220,9 +248,27 @@
}
int64_t ui_radiobuttons_get(UiInteger *i) {
- return 0;
+ NSMutableArray *buttons = (__bridge NSMutableArray*)i->obj;
+ int64_t index = 0;
+ for(UiRadioButton *b in buttons) {
+ if([b cell].state != 0) {
+ i->value = index + 1;
+ break;
+ }
+ index++;
+ }
+ return i->value;
}
void ui_radiobuttons_set(UiInteger *i, int64_t value) {
-
+ NSMutableArray *buttons = (__bridge NSMutableArray*)i->obj;
+ int64_t index = 1;
+ for(UiRadioButton *b in buttons) {
+ if(index == value) {
+ [b cell].state = NSControlStateValueOn;
+ } else {
+ [b cell].state = NSControlStateValueOff;
+ }
+ index++;
+ }
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/container.h
--- a/ui/cocoa/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -43,7 +43,7 @@
};
struct UiLayout {
- UiTri fill;
+ UiBool fill;
//UiBool newline;
//char *label;
UiBool hexpand;
@@ -56,13 +56,13 @@
};
#define UI_INIT_LAYOUT(args) (UiLayout) {\
- .fill = args.fill, \
- .hexpand = args.hexpand, \
- .vexpand = args.vexpand, \
- .hfill = args.hfill, \
- .vfill = args.vfill, \
- .colspan = args.colspan, \
- .rowspan = args.rowspan }
+ .fill = args->fill, \
+ .hexpand = args->hexpand, \
+ .vexpand = args->vexpand, \
+ .hfill = args->hfill, \
+ .vfill = args->vfill, \
+ .colspan = args->colspan, \
+ .rowspan = args->rowspan }
@protocol Container
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/container.m
--- a/ui/cocoa/container.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/container.m Sun Jul 20 22:04:39 2025 +0200
@@ -95,8 +95,8 @@
/* -------------------- public container functions --------------------- */
-static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, NSUserInterfaceLayoutOrientation orientation) {
- BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args.spacing];
+static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterfaceLayoutOrientation orientation) {
+ BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args->spacing];
box.translatesAutoresizingMaskIntoConstraints = false;
// add box to the parent
@@ -109,15 +109,15 @@
return (__bridge void*)box;
}
-UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationVertical);
}
-UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationHorizontal);
}
-UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
GridLayout *grid = [[GridLayout alloc] init];
grid.translatesAutoresizingMaskIntoConstraints = false;
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/graphics.h
--- a/ui/cocoa/graphics.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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.
- */
-
-#import "../ui/graphics.h"
-#import "toolkit.h"
-
-
-@interface UiCanvas : NSView {
- UiObject *object;
- ui_drawfunc callback;
- void *userdata;
-}
-
-- (UiObject*) object;
-- (void) setObject:(void*)obj;
-
-- (void*) userdata;
-- (void) setUserdata:(void*)d;
-
-- (ui_drawfunc) callback;
-- (void) setCallback: (ui_drawfunc)f;
-
-
-- (void)drawRect:(NSRect)rect;
-
-@end
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/graphics.m
--- a/ui/cocoa/graphics.m Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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.
- */
-
-#import
-#import
-#import
-
-#import "graphics.h"
-#import "container.h"
-#import "../common/context.h"
-
-
-
-@implementation UiCanvas
-
-- (UiObject*) object {
- return object;
-}
-
-- (void) setObject:(void*)obj {
- object = obj;
-}
-
-- (void*) userdata {
- return userdata;
-}
-
-- (void) setUserdata:(void*)d {
- userdata = d;
-}
-
-- (ui_drawfunc) callback {
- return callback;
-}
-- (void) setCallback: (ui_drawfunc)f {
- callback = f;
-}
-
-- (void) drawRect:(NSRect)rect {
- UiGraphics g;
- NSRect bounds = [self bounds];
- g.width = bounds.size.width;
- g.height = bounds.size.height;
-
- UiEvent ev;
- ev.obj = object;
- ev.window = object->window;
- ev.document = object->ctx->document;
-
- callback(&ev, &g, userdata);
-}
-
-@end
-
-
-UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) {
- UiContainer *ct = uic_get_current_container(obj);
-
- NSRect frame = ct->getframe(ct);
-
- UiCanvas *canvas = [[UiCanvas alloc]initWithFrame:frame];
- [canvas setObject: obj];
- [canvas setCallback: f];
- [canvas setUserdata: userdata];
- ct->add(ct, canvas);
-
- return canvas;
-}
-
-
-// drawing functions
-void ui_graphics_color(UiGraphics *gr, int red, int green, int blue) {
- float r = ((float)red) / 255.f;
- float g = ((float)green) / 255.f;
- float b = ((float)blue) / 255.f;
-
- NSColor *color = [NSColor colorWithCalibratedRed:r green:g blue:b alpha:1];
- [color set];
-}
-
-void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) {
- // translate y
- y = g->height - y - h;
-
- NSRect bounds;
- bounds.origin.x = x;
- bounds.origin.y = y;
- bounds.size.width = w;
- bounds.size.height = h;
-
- if(fill) {
- NSRectFill(bounds);
- } else {
- NSFrameRect(bounds);
- }
-}
-
-
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/menu.h
--- a/ui/cocoa/menu.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/menu.h Sun Jul 20 22:04:39 2025 +0200
@@ -31,6 +31,18 @@
#import "../common/menu.h"
+@interface MenuItem : NSObject
+
+@property (strong) NSString *itemId;
+@property UiMenuCheckItem *checkItem;
+@property UiMenuRadioItem *radioItem;
+@property ui_callback callback;
+@property void *userdata;
+
+- (MenuItem*)init:(int)itId;
+
+@end
+
void ui_menu_init(void);
typedef void(*ui_menu_add_f)(NSMenu*, int, UiMenuItemI*);
@@ -42,3 +54,5 @@
void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item);
void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item);
void add_menuitem_list_widget(NSMenu *parent, int i, UiMenuItemI *item);
+
+NSArray* ui_get_binding_items(void);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/menu.m
--- a/ui/cocoa/menu.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/menu.m Sun Jul 20 22:04:39 2025 +0200
@@ -30,9 +30,27 @@
#import
#import
#import
+#import
#import "menu.h"
#import "window.h"
+#import "EventData.h"
+
+#pragma GCC diagnostic ignored "-Wundeclared-selector"
+#pragma clang diagnostic ignored "-Wundeclared-selector"
+
+// holds all items that need bindings
+// value type: MenuItem*
+static NSMutableArray *bindingItems;
+
+@implementation MenuItem
+
+- (MenuItem*)init:(int)itId {
+ self.itemId = [[NSString alloc] initWithFormat:@"item%d", itId];
+ return self;
+}
+
+@end
static ui_menu_add_f createMenuItem[] = {
/* UI_MENU */ add_menu_widget,
@@ -67,20 +85,51 @@
void add_menuitem_widget(NSMenu *parent, int i, UiMenuItemI *item) {
UiMenuItem *it = (UiMenuItem*)item;
+
NSString *str = [[NSString alloc] initWithUTF8String:it->label];
- NSMenuItem *menuItem = [parent addItemWithTitle:str action:nil keyEquivalent:@""];
+ NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuItemAction:) keyEquivalent:@""];
+
+ if(it->callback) {
+ EventData *event = [[EventData alloc] init:it->callback userdata:it->userdata];
+ objc_setAssociatedObject(menuItem, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+ }
}
void add_menuseparator_widget(NSMenu *parent, int i, UiMenuItemI *item) {
-
+ NSMenuItem *menuItem = [NSMenuItem separatorItem];
+ [parent addItem:menuItem];
}
+static int nItem = 0;
+
void add_checkitem_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+ UiMenuCheckItem *it = (UiMenuCheckItem*)item;
+ NSString *str = [[NSString alloc] initWithUTF8String:it->label];
+ NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuCheckItemAction:) keyEquivalent:@""];
+
+ MenuItem *mItem = [[MenuItem alloc] init:nItem++];
+ mItem.callback = it->callback;
+ mItem.userdata = it->userdata;
+ mItem.checkItem = it;
+
+ objc_setAssociatedObject(menuItem, "menuitem", mItem, OBJC_ASSOCIATION_RETAIN);
+ [bindingItems addObject:mItem];
}
void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item) {
+ UiMenuRadioItem *it = (UiMenuRadioItem*)item;
+ NSString *str = [[NSString alloc] initWithUTF8String:it->label];
+ NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuRadioItemAction:) keyEquivalent:@""];
+
+ MenuItem *mItem = [[MenuItem alloc] init:nItem++];
+ mItem.callback = it->callback;
+ mItem.userdata = it->userdata;
+ mItem.radioItem = it;
+
+ objc_setAssociatedObject(menuItem, "menuitem", mItem, OBJC_ASSOCIATION_RETAIN);
+ [bindingItems addObject:mItem];
}
void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item) {
@@ -93,17 +142,25 @@
void ui_menu_init(void) {
+ bindingItems = [[NSMutableArray alloc] init];
+
UiMenu *menus_begin = uic_get_menu_list();
UiMenu *ls = menus_begin;
+ int index = 1;
while(ls) {
if(ls->item.type == UI_MENU) {
NSString *str = [[NSString alloc] initWithUTF8String:ls->label];
NSMenu *menu = [[NSMenu alloc] initWithTitle: str];
- NSMenuItem *menuItem = [[NSApp mainMenu] addItemWithTitle:str action:nil keyEquivalent:@""];
+ NSMenuItem *menuItem = [[NSApp mainMenu] insertItemWithTitle:str action:nil keyEquivalent:@"" atIndex:index];
[[NSApp mainMenu] setSubmenu:menu forItem:menuItem];
add_menu_items(menu, 0, ls);
}
ls = (UiMenu*)ls->item.next;
+ index++;
}
}
+
+NSArray* ui_get_binding_items(void) {
+ return bindingItems;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/resource.h
--- a/ui/cocoa/resource.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "../ui/toolkit.h"
-#import "../ui/properties.h"
-
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/resource.m
--- a/ui/cocoa/resource.m Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import
-#import
-#import
-
-#import "resource.h"
-#import "../common/properties.h"
-
-
-
-void ui_load_lang_def(char *locale, char *default_locale) {
- NSString *localeString = nil;
- char tmp[6];
- if(!locale) {
- NSString* lang = [[NSLocale currentLocale] localeIdentifier];
- if(lang) {
- localeString = lang;
- } else {
- [[NSString alloc]initWithUTF8String:default_locale];
- }
- } else {
- localeString = [[NSString alloc]initWithUTF8String:locale];
- }
-
- NSString *path = [[NSBundle mainBundle] pathForResource:localeString ofType:@"properties" inDirectory:@"locales"];
-
- const char *p = [path UTF8String];
-
- if(uic_load_language_file((char*)p)) {
- if(default_locale) {
- ui_load_lang_def(default_locale, NULL);
- } else {
- // cannot find any language file
- fprintf(stderr, "Ui Error: Cannot load language.\n");
- exit(-1);
- }
- }
-}
-
-void ui_locales_dir(char *path) {
- // empty
-}
-
-void ui_pixmaps_dir(char *path) {
- // empty
-}
\ No newline at end of file
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/stock.h
--- a/ui/cocoa/stock.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "toolkit.h"
-#import "../ui/stock.h"
-#import
-
-typedef struct UiStockItem {
- NSString *label;
- NSString *keyEquivalent;
- NSImage *image;
-} UiStockItem;
-
-void ui_stock_init();
-
-void ui_add_stock_item(char *stock_id, NSString *label, NSString *keyEquivalent, NSImage *image);
-
-UiStockItem* ui_get_stock_item(char *stock_id);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/stock.m
--- a/ui/cocoa/stock.m Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import
-#import
-
-#import "stock.h"
-#import "../common/properties.h"
-
-static UcxMap *stock_items;
-
-void ui_stock_init() {
- stock_items = ucx_map_new(64);
-
- ui_add_stock_item(UI_STOCK_NEW, @"New", @"n", nil);
- ui_add_stock_item(UI_STOCK_OPEN, @"Open", @"o", nil);
- ui_add_stock_item(UI_STOCK_SAVE, @"Save", @"s", nil);
- ui_add_stock_item(UI_STOCK_SAVE_AS, @"Save as ...", @"", nil);
- ui_add_stock_item(UI_STOCK_CLOSE, @"Close", @"w", nil);
- ui_add_stock_item(UI_STOCK_UNDO, @"Undo", @"z", nil);
- ui_add_stock_item(UI_STOCK_REDO, @"Redo", @"", nil);
- ui_add_stock_item(UI_STOCK_CUT, @"Cut", @"x", nil);
- ui_add_stock_item(UI_STOCK_COPY, @"Copy", @"c", nil);
- ui_add_stock_item(UI_STOCK_PASTE, @"Paste", @"v", nil);
- ui_add_stock_item(UI_STOCK_DELETE, @"Delete", @"", nil);
-
- ui_add_stock_item(UI_STOCK_GO_BACK, @"Back", @"", [NSImage imageNamed: NSImageNameGoLeftTemplate]);
- ui_add_stock_item(UI_STOCK_GO_FORWARD, @"Forward", @"", [NSImage imageNamed: NSImageNameGoRightTemplate]);
-}
-
-void ui_add_stock_item(char *stock_id, NSString *label, NSString *keyEquivalent, NSImage *image) {
- UiStockItem *i = malloc(sizeof(UiStockItem));
- i->label = label;
- i->keyEquivalent = keyEquivalent;
- i->image = image;
-
- ucx_map_cstr_put(stock_items, stock_id, i);
-}
-
-UiStockItem* ui_get_stock_item(char *stock_id) {
- UiStockItem *item = ucx_map_cstr_get(stock_items, stock_id);
- if(item) {
- char *label = uistr_n(stock_id);
- if(label) {
- NSString *str = [[NSString alloc]initWithUTF8String:label];
- item->label = str;
- }
- }
- return item;
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/text.h
--- a/ui/cocoa/text.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/text.h Sun Jul 20 22:04:39 2025 +0200
@@ -30,3 +30,20 @@
#import "../ui/text.h"
+
+void ui_textarea_save(UiText *text);
+void ui_textarea_destroy(UiText *text);
+void ui_textarea_restore(UiText *text);
+void ui_textarea_set(UiText *text, const char *str);
+char* ui_textarea_get(UiText *text);
+char* ui_textarea_getsubstr(UiText *text, int begin, int end);
+void ui_textarea_insert(UiText *text, int pos, char *str);
+void ui_textarea_setposition(UiText *text, int pos);
+int ui_textarea_position(UiText *text);
+void ui_textarea_setselection(UiText *text, int begin, int end);
+void ui_textarea_selection(UiText *text, int *begin, int *end);
+int ui_textarea_length(UiText *text);
+void ui_textarea_remove(UiText *text, int begin, int end);
+
+char* ui_textfield_get(UiString *s);
+void ui_textfield_set(UiString *s, const char *value);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/text.m
--- a/ui/cocoa/text.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/text.m Sun Jul 20 22:04:39 2025 +0200
@@ -31,7 +31,7 @@
#import "Container.h"
#import
-UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
+UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
NSTextView *textview = [[NSTextView alloc] init];
textview.autoresizingMask = NSViewWidthSizable;
textview.minSize = NSMakeSize(0, 0);
@@ -44,5 +44,161 @@
UiLayout layout = UI_INIT_LAYOUT(args);
ui_container_add(obj, scrollview, &layout, TRUE);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT);
+ if(var) {
+ UiText *text = var->value;
+ text->obj = (__bridge void*)textview;
+ ui_textarea_restore(text);
+
+ text->save = ui_textarea_save;
+ text->destroy = ui_textarea_destroy;
+ text->restore = ui_textarea_restore;
+ text->set = ui_textarea_set;
+ text->get = ui_textarea_get;
+ text->getsubstr = ui_textarea_getsubstr;
+ text->insert = ui_textarea_insert;
+ text->setposition = ui_textarea_setposition;
+ text->position = ui_textarea_position;
+ text->setselection = ui_textarea_setselection;
+ text->selection = ui_textarea_selection;
+ text->length = ui_textarea_length;
+ text->remove = ui_textarea_remove;
+ }
+
return (__bridge void*)scrollview;
}
+
+
+
+
+void ui_textarea_save(UiText *text) {
+
+}
+
+void ui_textarea_destroy(UiText *text) {
+ (void)(__bridge_transfer NSTextStorage*)text->data1;
+}
+
+void ui_textarea_restore(UiText *text) {
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSTextStorage *textStorage;
+ if(text->data1) {
+ textStorage = (__bridge NSTextStorage*)text->data1;
+
+ } else {
+ textStorage = [[NSTextStorage alloc] init];
+ }
+ [textview.layoutManager replaceTextStorage:textStorage];
+ text->data1 = (__bridge_retained void*)textStorage;
+}
+
+void ui_textarea_set(UiText *text, const char *str) {
+
+}
+
+char* ui_textarea_get(UiText *text) {
+ return NULL;
+}
+
+char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
+ return NULL;
+}
+
+void ui_textarea_insert(UiText *text, int pos, char *str) {
+
+}
+
+void ui_textarea_setposition(UiText *text, int pos) {
+
+}
+
+int ui_textarea_position(UiText *text) {
+ return 0;
+}
+
+void ui_textarea_setselection(UiText *text, int begin, int end) {
+
+}
+
+void ui_textarea_selection(UiText *text, int *begin, int *end) {
+
+}
+
+int ui_textarea_length(UiText *text) {
+ return 0;
+}
+
+void ui_textarea_remove(UiText *text, int begin, int end) {
+
+}
+
+
+
+/* -------------------------- TextField -------------------------- */
+
+static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs *args, BOOL password, BOOL frameless) {
+ NSTextField *textfield;
+ if(password) {
+ textfield = [[NSSecureTextField alloc] init];
+ } else {
+ textfield = [[NSTextField alloc] init];
+ }
+
+ if(frameless) {
+ [textfield setBezeled: NO];
+ }
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, textfield, &layout, FALSE);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
+ if(var) {
+ UiString *s = var->value;
+ if(s->value.ptr) {
+ textfield.stringValue = [[NSString alloc] initWithUTF8String:s->value.ptr];
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ }
+ s->obj = (__bridge void*)textfield;
+ s->get = ui_textfield_get;
+ s->set = ui_textfield_set;
+ }
+
+ return (__bridge void*)textfield;
+}
+
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
+ return textfield_create(obj, args, FALSE, FALSE);
+}
+
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args) {
+ return textfield_create(obj, args, FALSE, TRUE);
+}
+
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) {
+ return textfield_create(obj, args, TRUE, FALSE);
+}
+
+char* ui_textfield_get(UiString *s) {
+ NSTextField *textfield = (__bridge NSTextField*)s->obj;
+ NSString *str = textfield.stringValue;
+ const char *cstr = str.UTF8String;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = strdup(cstr);
+ s->value.free = free;
+ return s->value.ptr;
+}
+
+void ui_textfield_set(UiString *s, const char *value) {
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = NULL;
+ s->value.free = NULL;
+ NSTextField *textfield = (__bridge NSTextField*)s->obj;
+ textfield.stringValue = [[NSString alloc] initWithUTF8String:value];
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/toolbar.h
--- a/ui/cocoa/toolbar.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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.
- */
-
-#import "../ui/toolbar.h"
-#import "toolkit.h"
-#import
-
-
-@protocol UiToolItem
-- (NSToolbarItem *) createItem:(NSToolbar*)toolbar
- identifier:(NSString*)identifier
- object:(UiObject*)obj;
-
-- (void) addGroup:(int)group;
-
-- (UcxList*) groups;
-
-@end
-
-
-/*
- * UiToolbarStockItem
- *
- * creates a toolbar item from stock description
- */
-@interface UiToolbarStockItem : NSObject {
- char *name;
- char *stockid;
- ui_callback callback;
- void *userdata;
- UcxList *groups;
- BOOL isToggleButton;
-}
-
-- (UiToolbarStockItem*) initWithIdentifier:(char*)identifier
- stockID:(char*)sid
- callback:(ui_callback)f
- userdata:(void*)data;
-
-- (void) setIsToggleButton:(BOOL)t;
-
-
-@end
-
-/*
- * UiToolbarItem
- *
- * toolbar item with label and icon
- */
-@interface UiToolbarItem : NSObject {
- char *name;
- char *label;
- // icon
- ui_callback callback;
- void *userdata;
- UcxList *groups;
- BOOL isToggleButton;
-}
-
-- (UiToolbarItem*) initWithIdentifier:(char*)identifier
- label:(char*)lbl
- callback:(ui_callback)f
- userdata:(void*)data;
-
-- (void) setIsToggleButton:(BOOL)t;
-
-
-@end
-
-
-
-/*
- * UiToolbarDelegate
- */
-@interface UiToolbarDelegate : NSObject {
- NSMutableArray *allowedItems;
- NSMutableArray *defaultItems;
- NSMutableDictionary *items;
-}
-
-- (UiToolbarDelegate*) init;
-
-- (void) addDefault:(NSString*)identifier;
-
-- (void) addItem: (NSString*) identifier
- item: (NSObject*) item;
-
-@end
-
-
-/*
- * UiToolbar
- */
-@interface UiToolbar : NSToolbar {
- UiObject *obj;
-}
-
-- (UiToolbar*) initWithObject:(UiObject*)object;
-
-- (UiObject*) object;
-
-@end
-
-void ui_toolbar_init();
-void ui_toolbar_stock_button(char *name, char *stockid, BOOL toggle, ui_callback f, void *udata, va_list ap);
-NSToolbar* ui_create_toolbar(UiObject *obj);
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/toolbar.m
--- a/ui/cocoa/toolbar.m Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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.
- */
-
-#import
-#import
-#import
-#import
-#import
-
-#import "toolbar.h"
-#import "window.h"
-#import "stock.h"
-
-
-static UiToolbarDelegate* toolbar_delegate;
-
-/* --------------------- UiToolbarStockItem --------------------- */
-
-@implementation UiToolbarStockItem
-
-- (UiToolbarStockItem*) initWithIdentifier:(char*)identifier
- stockID:(char*)sid
- callback:(ui_callback)f
- userdata:(void*)data
-{
- name = identifier;
- stockid = sid;
- callback = f;
- userdata = data;
- groups = NULL;
- isToggleButton = NO;
- return self;
-}
-
-- (void) setIsToggleButton:(BOOL)t {
- isToggleButton = t;
-}
-
-- (void) addGroup:(int)group {
- groups = ucx_list_append(groups, (void*)(intptr_t)group);
-}
-
-
-- (NSToolbarItem *) createItem:(NSToolbar*)toolbar
- identifier:(NSString*)identifier
- object:(UiObject*)obj
-{
- UiStockItem *s = ui_get_stock_item(stockid);
- if(s == nil) {
- printf("cannot find stock item\n");
- return nil;
- }
-
- NSToolbarItem *item = [[[NSToolbarItem alloc] initWithItemIdentifier:
- identifier] autorelease];
- //[item setLabel:[s label]];
- //[item setPaletteLabel:[s label]];
- [item setLabel:s->label];
- [item setPaletteLabel:@"Operation"];
-
- // create button ...
- NSRect frame = NSMakeRect(0, 0, 40, 22);
- //NSSearchField *sf = [[NSSearchField alloc]initWithFrame:frame];
- NSButton *button = [[NSButton alloc]initWithFrame:frame];
- //[button setImage:[s buttonImage]];
- //[button setImage:[NSImage imageNamed: NSImageNameAddTemplate]];
- if(s->image) {
- [button setImage:s->image];
- } else {
- [button setImage:[NSImage imageNamed: NSImageNameRemoveTemplate]];
- }
- [button setBezelStyle: NSTexturedRoundedBezelStyle];
-
- // event
- EventWrapper *event = [[EventWrapper alloc]
- initWithData:userdata callback:callback];
- if(isToggleButton) {
- [button setButtonType: NSPushOnPushOffButton];
- [button setAction:@selector(handleToggleEvent:)];
- } else {
- [button setAction:@selector(handleEvent:)];
- }
- [button setTarget:event];
-
- if(groups) {
- uic_add_group_widget(obj->ctx, item, groups);
- }
-
- [item setView:button];
- return item;
-}
-
-- (UcxList*) groups {
- return groups;
-}
-
-@end
-
-
-/* --------------------- UiToolbarItem --------------------- */
-
-@implementation UiToolbarItem
-
-- (UiToolbarItem*) initWithIdentifier:(char*)identifier
- label:(char*)lbl
- callback:(ui_callback)f
- userdata:(void*)data
-{
- name = identifier;
- label = lbl;
- callback = f;
- userdata = data;
- groups = NULL;
- isToggleButton = NO;
- return self;
-}
-
-- (void) setIsToggleButton:(BOOL)t {
- isToggleButton = t;
-}
-
-- (void) addGroup:(int)group {
- groups = ucx_list_append(groups, (void*)(intptr_t)group);
-}
-
-
-- (NSToolbarItem *) createItem:(NSToolbar*)toolbar
- identifier:(NSString*)identifier
- object:(UiObject*)obj
-{
- NSToolbarItem *item = [[[NSToolbarItem alloc] initWithItemIdentifier:
- identifier] autorelease];
- //[item setLabel:[s label]];
- //[item setPaletteLabel:[s label]];
- NSString *l = [[NSString alloc]initWithUTF8String:label];
- [item setLabel:l];
- [item setPaletteLabel:@"Operation"];
-
- // create button ...
- NSRect frame = NSMakeRect(0, 0, 40, 22);
- //NSSearchField *sf = [[NSSearchField alloc]initWithFrame:frame];
- NSButton *button = [[NSButton alloc]initWithFrame:frame];
- //[button setImage:[s buttonImage]];
- //[button setImage:[NSImage imageNamed: NSImageNameAddTemplate]];
-
- // TODO: image
- [button setImage:[NSImage imageNamed: NSImageNameRemoveTemplate]];
-
- [button setBezelStyle: NSTexturedRoundedBezelStyle];
-
- // event
- EventWrapper *event = [[EventWrapper alloc]
- initWithData:userdata callback:callback];
- if(isToggleButton) {
- [button setButtonType: NSPushOnPushOffButton];
- [button setAction:@selector(handleToggleEvent:)];
- } else {
- [button setAction:@selector(handleEvent:)];
- }
- [button setTarget:event];
-
- if(groups) {
- uic_add_group_widget(obj->ctx, item, groups);
- }
-
- [item setView:button];
- return item;
-}
-
-- (UcxList*) groups {
- return groups;
-}
-
-@end
-
-
-/* --------------------- UiToolbarDelegate --------------------- */
-
-@implementation UiToolbarDelegate
-
-- (UiToolbarDelegate*) init {
- allowedItems = [[NSMutableArray alloc]initWithCapacity: 16];
- defaultItems = [[NSMutableArray alloc]initWithCapacity: 16];
- items = [[NSMutableDictionary alloc] init];
- return self;
-}
-
-- (void) addDefault:(NSString*)identifier {
- [defaultItems addObject: identifier];
-}
-
-- (void) addItem: (NSString*) identifier
- item: (NSObject*) item
-{
- [allowedItems addObject: identifier];
- [items setObject: item forKey:identifier];
-}
-
-/*
-- (void) addStockItem:(char*)name
- stockID:(char*)sid
- callback:(ui_callback)f
- data:(void*)userdata
-{
- UiToolbarStockItem *item = [[UiToolbarStockItem alloc]initWithData:name
- stockID:sid callback:f data:userdata];
-
- NSString *s = [[NSString alloc]initWithUTF8String:name];
- [allowedItems addObject: s];
- [items setObject: item forKey:s];
-}
-*/
-
-// implementation of NSToolbarDelegate methods
-- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
- NSMutableArray *i = [[NSMutableArray alloc]
- initWithCapacity:[allowedItems count] + 3];
- [i addObject: NSToolbarFlexibleSpaceItemIdentifier];
- [i addObject: NSToolbarSpaceItemIdentifier];
- [i addObject: NSToolbarSeparatorItemIdentifier];
- for(id item in allowedItems) {
- [i addObject: item];
- }
-
- return i;
-}
-
-- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
- return defaultItems;
-}
-
-- (NSToolbarItem *) toolbar:(NSToolbar*)toolbar
- itemForItemIdentifier:(NSString*)identifier
- willBeInsertedIntoToolbar:(BOOL)flag
-{
- Protocol *item = @protocol(UiToolItem);
- item = [items objectForKey: identifier];
-
- // get UiObject from toolbar
- UiObject *obj = [(UiToolbar*)toolbar object];
-
- // create new NSToolbarItem
- return [item createItem:toolbar identifier:identifier object:obj];
-}
-
-@end
-
-
-@implementation UiToolbar
-
-- (UiToolbar*) initWithObject:(UiObject*)object {
- [self initWithIdentifier: @"MainToolbar"];
- obj = object;
- return self;
-}
-
-- (UiObject*) object {
- return obj;
-}
-
-@end
-
-
-/* --------------------- functions --------------------- */
-
-void ui_toolbar_init() {
- toolbar_delegate = [[UiToolbarDelegate alloc]init];
-}
-
-void ui_toolitem(char *name, char *label, ui_callback f, void *udata) {
- UiToolbarItem *item = [[UiToolbarItem alloc]
- initWithIdentifier: name
- label: label
- callback: f
- userdata: udata];
-
- NSString *identifier = [[NSString alloc]initWithUTF8String:name];
- [toolbar_delegate addItem: identifier item: item];
-}
-
-void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *udata) {
- ui_toolitem_stgr(name, stockid, f, udata, -1);
-}
-
-void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *udata, ...) {
- va_list ap;
- va_start(ap, udata);
- ui_toolbar_stock_button(name, stockid, NO, f, udata, ap);
- va_end(ap);
-}
-
-void ui_toolitem_toggle_st(char *name, char *stockid, ui_callback f, void *udata) {
- ui_toolitem_toggle_stgr(name, stockid, f, udata, -1);
-}
-
-void ui_toolitem_toggle_stgr(char *name, char *stockid, ui_callback f, void *udata, ...) {
- va_list ap;
- va_start(ap, udata);
- ui_toolbar_stock_button(name, stockid, YES, f, udata, ap);
- va_end(ap);
-}
-
-
-void ui_toolbar_stock_button(char *name, char *stockid, BOOL toggle, ui_callback f, void *udata, va_list ap) {
- UiToolbarStockItem *item = [[UiToolbarStockItem alloc]
- initWithIdentifier: name
- stockID: stockid
- callback: f
- userdata: udata];
- [item setIsToggleButton: toggle];
- NSString *identifier = [[NSString alloc]initWithUTF8String:name];
- [toolbar_delegate addItem: identifier item: item];
-
- // add groups
- int group;
- while((group = va_arg(ap, int)) != -1) {
- [item addGroup: group];
- }
-}
-
-
-void ui_toolbar_add_default(char *name) {
- NSString *identifier = [[NSString alloc]initWithUTF8String:name];
- [toolbar_delegate addDefault: identifier];
-}
-
-NSToolbar* ui_create_toolbar(UiObject *obj) {
- UiToolbar *toolbar = [[UiToolbar alloc] initWithObject:obj];
- [toolbar setDelegate: toolbar_delegate];
- [toolbar setAllowsUserCustomization: true];
- return toolbar;
-}
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/toolkit.m
--- a/ui/cocoa/toolkit.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/toolkit.m Sun Jul 20 22:04:39 2025 +0200
@@ -46,9 +46,11 @@
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
+
+static UiBool exit_on_shutdown;
/* ------------------- App Init / Event Loop functions ------------------- */
@@ -89,6 +91,10 @@
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_cocoa_onstartup(void) {
UiEvent e;
e.obj = NULL;
@@ -127,6 +133,9 @@
void ui_main(void) {
NSApplicationMain(app_argc, app_argv);
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
/* ------------------- Window Visibility functions ------------------- */
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/tree.h
--- a/ui/cocoa/tree.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
- #import "../ui/tree.h"
- #import "toolkit.h"
-
-
-@interface UiTableDataSource : NSObject {
- UiList *data;
- UiModelInfo *info;
- UiListSelection *lastSelection;
-}
-
-- (id)initWithData:(UiList*)list modelInfo:(UiModelInfo*)modelinfo;
-
-- (void)handleDoubleAction:(id)sender;
-
-@end
-
-
-char* ui_type_to_string(UiModelType type, void *data, BOOL *free);
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/tree.m
--- a/ui/cocoa/tree.m Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import
-#import
-
-#import "tree.h"
-#import "container.h"
-#import "window.h"
-#import "../common/context.h"
-#import
-
-@implementation UiTableDataSource
-
-- (id)initWithData:(UiList*)list modelInfo:(UiModelInfo*)modelinfo {
- data = list;
- info = modelinfo;
- lastSelection = NULL;
- return self;
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableview {
- return data->count(data);
-}
-
-- (id)tableView: (NSTableView*)tableview
- objectValueForTableColumn:(NSTableColumn*)column
- row:(NSInteger)row
-{
- int column_index = [[column identifier]intValue];
-
- void *row_data = data->get(data, row);
- void *cell_data = info->getvalue(row_data, column_index);
-
- BOOL f = false;
- char *str = ui_type_to_string(info->types[column_index], cell_data, &f);
- NSString *s = [[NSString alloc]initWithUTF8String:str];
- return s;
-}
-
-- (void)tableView:(NSTableView *)tableview
- setObjectValue:(id)object
- forTableColumn:(NSTableColumn *)column
- row:(NSInteger)row
-{
- int column_index = [[column identifier]intValue];
-
- // TODO
-}
-
-- (void)tableViewSelectionDidChange:(NSNotification *)notification {
- NSTableView *tableview = (NSTableView*)notification.object;
-
- // create selection object
- UiListSelection *selection = malloc(sizeof(UiListSelection));
- selection->count = [tableview numberOfSelectedRows];
-
- selection->rows = calloc(selection->count, sizeof(int));
- NSIndexSet *indices = [tableview selectedRowIndexes];
- NSUInteger index = [indices firstIndex];
- int i=0;
- while (index!=NSNotFound) {
- selection->rows[i] = index;
- index = [indices indexGreaterThanIndex:index];
- i++;
- }
-
- // create event object
- UiEvent event;
- NSWindow *activeWindow = [NSApp keyWindow];
- if([activeWindow class] == [UiCocoaWindow class]) {
- event.obj = [(UiCocoaWindow*)activeWindow object];
- event.window = event.obj->window;
- event.document = event.obj->ctx->document;
- } else {
- event.window = NULL;
- event.document = NULL;
- }
- event.eventdata = selection;
- event.intval = selection->count == 0 ? -1 : selection->rows[0];
-
- // callback
- info->selection(&event, info->userdata);
-
- // cleanup
- if(lastSelection) {
- free(lastSelection->rows);
- free(lastSelection);
- }
- lastSelection = selection;
-}
-
-- (void)handleDoubleAction:(id)sender {
- // create event object
- UiEvent event;
- NSWindow *activeWindow = [NSApp keyWindow];
- if([activeWindow class] == [UiCocoaWindow class]) {
- event.obj = [(UiCocoaWindow*)activeWindow object];
- event.window = event.obj->window;
- event.document = event.obj->ctx->document;
- } else {
- event.window = NULL;
- event.document = NULL;
- }
- event.eventdata = lastSelection;
- event.intval = lastSelection->count == 0 ? -1 : lastSelection->rows[0];
-
- info->activate(&event, info->userdata);
-}
-
-- (BOOL)tableView:(NSTableView *)tableview isGroupRow:(NSInteger)row {
- return NO;
-}
-
-@end
-
-
-UIWIDGET ui_table(UiObject *obj, UiList *model, UiModelInfo *modelinfo) {
- UiContainer *ct = uic_get_current_container(obj);
- NSRect frame = ct->getframe(ct);
-
- NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:frame];
- [scrollview setHasVerticalScroller:YES];
- //[scrollvew setHasHorizontalScroller:YES];
- [scrollview setBorderType:NSNoBorder];
- //[scrollview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
-
- NSTableView *tableview = [[NSTableView alloc]initWithFrame:frame];
- [scrollview setDocumentView:tableview];
- [tableview setAllowsMultipleSelection: YES];
- //[tableview setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
-
- // add columns
- for(int i=0;icolumns;i++) {
- NSString *cid = [[NSString alloc]initWithFormat: @"%d", i];
- NSTableColumn *column = [[NSTableColumn alloc]initWithIdentifier:cid];
-
- NSString *title = [[NSString alloc]initWithUTF8String: modelinfo->titles[i]];
- [[column headerCell] setStringValue:title];
-
- [tableview addTableColumn:column];
- }
-
- UiTableDataSource *source = [[UiTableDataSource alloc]initWithData:model modelInfo:modelinfo];
- [tableview setDataSource:source];
- [tableview setDelegate:source];
-
- [tableview setDoubleAction:@selector(handleDoubleAction:)];
- [tableview setTarget:source];
-
-
- ct->add(ct, scrollview);
- return scrollview;
-}
-
-
-UIWIDGET ui_listview_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
- UiContainer *ct = uic_get_current_container(obj);
- NSRect frame = ct->getframe(ct);
-
- NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:frame];
- [scrollview setHasVerticalScroller:YES];
-
- [scrollview setBorderType:NSNoBorder];
-
- NSTableView *tableview = [[NSTableView alloc]initWithFrame:frame];
- [scrollview setDocumentView:tableview];
- [tableview setAllowsMultipleSelection: NO];
-
- // add single column
- NSTableColumn *column = [[NSTableColumn alloc]initWithIdentifier:@"c"];
- [tableview addTableColumn:column];
-
- // create model info
- UiModelInfo *modelinfo = ui_model_info(obj->ctx, UI_STRING, -1);
-
- // add source
- UiTableDataSource *source = [[UiTableDataSource alloc]initWithData:list->list modelInfo:modelinfo];
-
- [tableview setDataSource:source];
- [tableview setDelegate:source];
-
- [tableview setDoubleAction:@selector(handleDoubleAction:)];
- [tableview setTarget:source];
-
- ct->add(ct, scrollview);
- return scrollview;
-}
-
-UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
- UiListPtr *listptr = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr));
- listptr->list = list;
- return ui_listview_var(obj, listptr, getvalue, f, udata);
-}
-
-UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
- UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST);
- if(var) {
- UiListVar *value = var->value;
- return ui_listview_var(obj, value->listptr, getvalue, f, udata);
- } else {
- // TODO: error
- }
- return NULL;
-}
-
-
-// TODO: motif code duplicate
-char* ui_type_to_string(UiModelType type, void *data, BOOL *free) {
- switch(type) {
- case UI_STRING: *free = FALSE; return data;
- case UI_INTEGER: {
- *free = TRUE;
- int *val = data;
- sstr_t str = ucx_asprintf(ucx_default_allocator(), "%d", *val);
- return str.ptr;
- }
- }
- *free = FALSE;
- return NULL;
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/cocoa/window.m
--- a/ui/cocoa/window.m Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/cocoa/window.m Sun Jul 20 22:04:39 2025 +0200
@@ -31,6 +31,8 @@
#import "MainWindow.h"
#import "WindowManager.h"
+#import
+
#include "../ui/window.h"
#include "../ui/properties.h"
#include "../common/context.h"
@@ -39,6 +41,7 @@
#include
+
static UiObject* create_window(const char *title, BOOL simple) {
CxMempool *mp = cxMempoolCreateSimple(256);
UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
@@ -52,6 +55,11 @@
obj->wobj = (__bridge void*)window;
+ MainWindowController *controller = [[MainWindowController alloc] initWithWindow:obj window:window];
+ window.windowController = controller;
+ [window setNextResponder:(NSResponder*)controller];
+ objc_setAssociatedObject(window, "windowcontroller", controller, OBJC_ASSOCIATION_RETAIN);
+
return obj;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/args.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/args.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,1736 @@
+/*
+ * 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 "args.h"
+
+#include
+#include
+
+#include "../ui/container.h"
+
+
+/* ---------------------------- UiDialogArgs ---------------------------- */
+
+UiDialogArgs* ui_dialog_args_new(void) {
+ UiDialogArgs *args = malloc(sizeof(UiDialogArgs));
+ memset(args, 0, sizeof(UiDialogArgs));
+ return args;
+}
+
+void ui_dialog_args_set_title(UiDialogArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialog_args_set_content(UiDialogArgs *args, const char *str) {
+ args->content = strdup(str);
+}
+
+void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label) {
+ args->button1_label = strdup(label);
+}
+
+void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label) {
+ args->button2_label = strdup(label);
+}
+
+void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label) {
+ args->closebutton_label = strdup(label);
+}
+
+void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value) {
+ args->input_value = strdup(value);
+}
+
+void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input) {
+ args->input = input;
+}
+
+void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password) {
+ args->password = password;
+}
+
+void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb) {
+ args->result = cb;
+}
+
+void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata) {
+ args->resultdata = userdata;
+}
+
+void ui_dialog_args_free(UiDialogArgs *args) {
+ free((void*)args->title);
+ free((void*)args->button1_label);
+ free((void*)args->button2_label);
+ free((void*)args->content);
+ free((void*)args->closebutton_label);
+ free((void*)args->input_value);
+ free(args);
+}
+
+
+/* -------------------------- UiDialogWindowArgs -------------------------- */
+
+UiDialogWindowArgs* ui_dialogwindow_args_new(void) {
+ UiDialogWindowArgs *args = malloc(sizeof(UiDialogWindowArgs));
+ memset(args, 0, sizeof(UiDialogWindowArgs));
+ return args;
+}
+
+void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value) {
+ args->modal = value;
+}
+
+void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value) {
+ args->titlebar_buttons = value;
+}
+
+void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value) {
+ args->show_closebutton = value;
+}
+
+void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton1 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton2 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton3 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton4 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button) {
+ args->default_button = button;
+}
+
+void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width) {
+ args->width = width;
+}
+
+void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height) {
+ args->height = height;
+}
+
+void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb) {
+ args->onclick = cb;
+}
+
+void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata) {
+ args->onclickdata = userdata;
+}
+
+void ui_dialogwindow_args_free(UiDialogWindowArgs *args) {
+ free((void*)args->title);
+ free((void*)args->lbutton1);
+ 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(args);
+}
+
+
+/* ---------------------------- UiMenuItemArgs ---------------------------- */
+
+UiMenuItemArgs* ui_menuitem_args_new(void) {
+ UiMenuItemArgs *args = malloc(sizeof(UiMenuItemArgs));
+ memset(args, 0, sizeof(UiMenuItemArgs));
+ return args;
+}
+
+void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid) {
+ args->stockid = strdup(stockid);
+}
+
+void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon) {
+ args->icon = strdup(icon);
+}
+
+void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback) {
+ args->onclick = callback;
+}
+
+void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) {
+ args->onclickdata = onclickdata;
+}
+
+void ui_menuitem_args_free(UiMenuItemArgs *args) {
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free(args);
+}
+
+
+/* ---------------------------- UiMenuToggleItemArgs ---------------------------- */
+
+UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void) {
+ UiMenuToggleItemArgs *args = malloc(sizeof(UiMenuToggleItemArgs));
+ memset(args, 0, sizeof(UiMenuToggleItemArgs));
+ return args;
+}
+
+void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid) {
+ args->stockid = strdup(stockid);
+}
+
+void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon) {
+ args->icon = strdup(icon);
+}
+
+void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback) {
+ args->onchange = callback;
+}
+
+void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onclickdata) {
+ args->onchangedata = onclickdata;
+}
+
+void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) {
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free((void*)args->varname);
+ free(args);
+}
+
+/* --------------------------- UiMenuItemListArgs --------------------------- */
+
+UiMenuItemListArgs* ui_menuitemlist_args_new(void) {
+ UiMenuItemListArgs *args = malloc(sizeof(UiMenuItemListArgs));
+ memset(args, 0, sizeof(UiMenuItemListArgs));
+ return args;
+}
+
+void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func) {
+ args->getvalue = func;
+}
+
+void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback) {
+ args->onselect = callback;
+}
+
+void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data){
+ args->onselectdata = data;
+}
+
+void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value) {
+ args->addseparator = value;
+}
+
+void ui_menuitemlist_args_free(UiMenuItemListArgs *args){
+ free((void*)args->varname);
+ free(args);
+}
+
+/* --------------------------- UiToolbarItemArgs --------------------------- */
+
+UiToolbarItemArgs* ui_toolbar_item_args_new(void) {
+ UiToolbarItemArgs *args = malloc(sizeof(UiToolbarItemArgs));
+ memset(args, 0, sizeof(UiToolbarItemArgs));
+ return args;
+}
+
+void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid) {
+ args->stockid = strdup(stockid);
+}
+
+void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon) {
+ args->icon = strdup(icon);
+}
+
+void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback) {
+ args->onclick = callback;
+}
+
+void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata) {
+ args->onclickdata = onclickdata;
+}
+
+void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *groups) {
+ // TODO
+}
+void ui_toolbar_item_args_free(UiToolbarItemArgs *args) {
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free(args);
+}
+
+/* ---------------------------- UiToolbarToggleItemArgs ---------------------------- */
+
+UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void) {
+ UiToolbarToggleItemArgs *args = malloc(sizeof(UiToolbarToggleItemArgs));
+ memset(args, 0, sizeof(UiToolbarToggleItemArgs));
+ return args;
+}
+
+
+void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+
+void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid) {
+ args->stockid = strdup(stockid);
+}
+
+
+void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon) {
+ args->icon = strdup(icon);
+}
+
+
+void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+
+void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback) {
+ args->onchange = callback;
+}
+
+
+void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata) {
+ args->onchangedata = onchangedata;
+}
+
+
+void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *groups) {
+ // TODO
+}
+
+
+void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free((void*)args->varname);
+ free(args);
+}
+
+/* ---------------------------- UiToolbarMenuArgs ---------------------------- */
+
+
+UiToolbarMenuArgs* ui_toolbar_menu_args_new(void) {
+ UiToolbarMenuArgs *args = malloc(sizeof(UiToolbarMenuArgs));
+ memset(args, 0, sizeof(UiToolbarMenuArgs));
+ return args;
+}
+
+
+void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+
+void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid) {
+ args->stockid = strdup(stockid);
+}
+
+
+void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon) {
+ args->icon = strdup(icon);
+}
+
+
+void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args) {
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free(args);
+}
+
+
+/* ---------------------------- UiContainerArgs ---------------------------- */
+
+UiContainerArgs* ui_container_args_new(void) {
+ UiContainerArgs *args = malloc(sizeof(UiContainerArgs));
+ memset(args, 0, sizeof(UiContainerArgs));
+ return args;
+}
+
+void ui_container_args_set_fill(UiContainerArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_container_args_set_hexpand(UiContainerArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_container_args_set_vexpand(UiContainerArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_container_args_set_hfill(UiContainerArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_container_args_set_vfill(UiContainerArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_container_args_set_override_defaults(UiContainerArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_container_args_set_colspan(UiContainerArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value) {
+ args->def_hexpand = value;
+}
+
+
+void ui_container_args_set_def_vexpand(UiContainerArgs *args, UiBool value) {
+ args->def_vexpand = value;
+}
+
+
+void ui_container_args_set_def_hfill(UiContainerArgs *args, UiBool value) {
+ args->def_hfill = value;
+}
+
+
+void ui_container_args_set_def_vfill(UiContainerArgs *args, UiBool value) {
+ args->def_vfill = value;
+}
+
+
+void ui_container_args_set_name(UiContainerArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_container_args_set_style_class(UiContainerArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+
+void ui_container_args_set_margin(UiContainerArgs *args, int value) {
+ args->margin = value;
+}
+
+
+void ui_container_args_set_spacing(UiContainerArgs *args, int value) {
+ args->spacing = value;
+}
+
+
+void ui_container_args_set_columnspacing(UiContainerArgs *args, int value) {
+ args->columnspacing = value;
+}
+
+
+void ui_container_args_set_rowspacing(UiContainerArgs *args, int value) {
+ args->rowspacing = value;
+}
+
+
+void ui_container_args_free(UiContainerArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free(args);
+}
+
+
+/* ------------------------------- UiFrameArgs ------------------------------*/
+
+UiFrameArgs* ui_frame_args_new(void) {
+ UiFrameArgs *args = malloc(sizeof(UiFrameArgs));
+ memset(args, 0, sizeof(UiContainerArgs));
+ return args;
+}
+
+
+void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_frame_args_set_hexpand(UiFrameArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_frame_args_set_vexpand(UiFrameArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_frame_args_set_hfill(UiFrameArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_frame_args_set_vfill(UiFrameArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_frame_args_set_rowspan(UiFrameArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_frame_args_set_name(UiFrameArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+
+void ui_frame_args_set_margin(UiFrameArgs *args, int value) {
+ args->margin = value;
+}
+
+
+void ui_frame_args_set_spacing(UiFrameArgs *args, int value) {
+ args->spacing = value;
+}
+
+
+void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value) {
+ args->columnspacing = value;
+}
+
+
+void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value) {
+ args->rowspacing = value;
+}
+
+
+void ui_frame_args_set_expanded(UiFrameArgs *args, UiBool value) {
+ args->isexpanded = value;
+}
+
+
+void ui_frame_args_set_label(UiFrameArgs *args, const char *label) {
+ args->label = strdup(label);
+}
+
+
+void ui_frame_args_free(UiFrameArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->label);
+ free(args);
+}
+
+
+/* ---------------------------- UiSidebarArgs -------------------------------*/
+
+UiSidebarArgs* ui_sidebar_args_new(void) {
+ UiSidebarArgs *args = malloc(sizeof(UiSidebarArgs));
+ memset(args, 0, sizeof(UiSidebarArgs));
+ return args;
+}
+
+
+void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+
+void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value) {
+ args->margin = value;
+}
+
+
+void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value) {
+ args->spacing = value;
+}
+
+
+void ui_sidebar_args_free(UiSidebarArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free(args);
+}
+
+
+/* --------------------------- UiSplitPaneArgs ------------------------------*/
+
+UiSplitPaneArgs* ui_splitpane_args_new(void) {
+ UiSplitPaneArgs *args = malloc(sizeof(UiSplitPaneArgs));
+ memset(args, 0, sizeof(UiSplitPaneArgs));
+ return args;
+}
+
+
+void ui_splitpane_args_set_fill(UiSplitPaneArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_splitpane_args_set_hexpand(UiSplitPaneArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+
+void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value) {
+ args->margin = value;
+}
+
+
+void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value) {
+ args->spacing = value;
+}
+
+
+void ui_splitpane_args_set_columnspacing(UiSplitPaneArgs *args, int value) {
+ args->columnspacing = value;
+}
+
+
+void ui_splitpane_args_set_rowspacing(UiSplitPaneArgs *args, int value) {
+ args->rowspacing = value;
+}
+
+
+void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos) {
+ args->initial_position = pos;
+}
+
+
+void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+
+void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value) {
+ args->value = value;
+}
+
+void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max) {
+ args->max_panes = max;
+}
+
+
+void ui_splitpane_args_free(UiSplitPaneArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free(args);
+}
+
+
+/* ------------------------- UiLabelArgs ----------------------------*/
+
+
+UiLabelArgs* ui_label_args_new(void) {
+ UiLabelArgs *args = malloc(sizeof(UiLabelArgs));
+ memset(args, 0, sizeof(UiLabelArgs));
+ return args;
+}
+
+
+void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_label_args_set_colspan(UiLabelArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_label_args_set_name(UiLabelArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_label_args_set_style_class(UiLabelArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_label_args_set_label(UiLabelArgs *args, const char *label){
+ args->label = strdup(label);
+}
+
+
+void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align) {
+ args->align = align;
+}
+
+void ui_label_args_set_style(UiLabelArgs *args, UiLabelStyle style) {
+ args->style = style;
+}
+
+void ui_label_args_set_varname(UiLabelArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_label_args_set_value(UiLabelArgs *args, UiString *value) {
+ args->value = value;
+}
+
+void ui_label_args_free(UiLabelArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->label);
+ free((void*)args->varname);
+ free(args);
+}
+
+
+/* ------------------------- UiProgressbarArgs ----------------------------*/
+
+
+UiProgressbarArgs* ui_progressbar_args_new(void) {
+ UiProgressbarArgs *args = malloc(sizeof(UiProgressbarArgs));
+ memset(args, 0, sizeof(UiProgressbarArgs));
+ return args;
+}
+
+
+void ui_progressbar_args_set_fill(UiProgressbarArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_progressbar_args_set_hexpand(UiProgressbarArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_progressbar_args_set_vexpand(UiProgressbarArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_progressbar_args_set_hfill(UiProgressbarArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_progressbar_args_set_vfill(UiProgressbarArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_progressbar_args_set_rowspan(UiProgressbarArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_progressbar_args_set_name(UiProgressbarArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_progressbar_args_set_style_class(UiProgressbarArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_progressbar_args_set_min(UiProgressbarArgs *args, double min) {
+ args->min = min;
+}
+
+void ui_progressbar_args_set_max(UiProgressbarArgs *args, double max) {
+ args->max = max;
+}
+
+void ui_progressbar_args_set_varname(UiProgressbarArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value) {
+ args->value = value;
+}
+
+void ui_progressbar_args_free(UiProgressbarArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free(args);
+}
+
+
+/* ------------------------- UiProgressbarSpinnerArgs ----------------------------*/
+
+UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void) {
+ UiProgressbarSpinnerArgs *args = malloc(sizeof(UiProgressbarSpinnerArgs));
+ memset(args, 0, sizeof(UiProgressbarSpinnerArgs));
+ return args;
+}
+
+void ui_progress_spinner_args_set_fill(UiProgressbarSpinnerArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_progress_spinner_args_set_hexpand(UiProgressbarSpinnerArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+void ui_progress_spinner_args_set_vexpand(UiProgressbarSpinnerArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+void ui_progress_spinner_args_set_hfill(UiProgressbarSpinnerArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+void ui_progress_spinner_args_set_vfill(UiProgressbarSpinnerArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+void ui_progress_spinner_args_set_rowspan(UiProgressbarSpinnerArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+void ui_progress_spinner_args_set_style_class(UiProgressbarSpinnerArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_progress_spinner_args_set_varname(UiProgressbarSpinnerArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiInteger *value) {
+ args->value = value;
+}
+
+void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free(args);
+}
+
+
+/* ---------------------------- UiButtonArgs -------------------------------*/
+
+UiButtonArgs* ui_button_args_new(void) {
+ UiButtonArgs *args = malloc(sizeof(UiButtonArgs));
+ memset(args, 0, sizeof(UiButtonArgs));
+ return args;
+}
+
+
+void ui_button_args_set_fill(UiButtonArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_button_args_set_hexpand(UiButtonArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_button_args_set_colspan(UiButtonArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_button_args_set_name(UiButtonArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_button_args_set_label(UiButtonArgs *args, const char *label){
+ args->label = strdup(label);
+}
+
+
+void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid){
+ args->stockid = strdup(stockid);
+}
+
+
+void ui_button_args_set_icon(UiButtonArgs *args, const char *icon){
+ args->icon = strdup(icon);
+}
+
+
+void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype){
+ args->labeltype = labeltype;
+}
+
+void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback){
+ args->onclick = callback;
+}
+
+
+void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
+ args->onclickdata = onclickdata;
+}
+
+void ui_button_args_set_groups(UiButtonArgs *args, int *groups){
+ // TODO
+}
+
+void ui_button_args_free(UiButtonArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free((void*)args->groups);
+ free(args);
+}
+
+
+/* ------------------------- UiToggleArgs ----------------------------*/
+
+
+UiToggleArgs* ui_toggle_args_new(void) {
+ UiToggleArgs *args = malloc(sizeof(UiToggleArgs));
+ memset(args, 0, sizeof(UiToggleArgs));
+ return args;
+}
+
+
+void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_toggle_args_set_name(UiToggleArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_toggle_args_set_label(UiToggleArgs *args, const char *label){
+ args->label = strdup(label);
+}
+
+
+void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid){
+ args->stockid = strdup(stockid);
+}
+
+
+void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon){
+ args->icon = strdup(icon);
+}
+
+
+void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype){
+ args->labeltype = labeltype;
+}
+
+void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback){
+ args->onchange = callback;
+}
+
+
+void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
+ args->onchangedata = onchangedata;
+}
+
+void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+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_groups(UiToggleArgs *args, int *groups){
+ // TODO
+}
+
+void ui_toggle_args_free(UiToggleArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->label);
+ free((void*)args->stockid);
+ free((void*)args->icon);
+ free((void*)args->varname);
+ free((void*)args->groups);
+ free(args);
+}
+
+
+/* ------------------------- UiListArgs ----------------------------*/
+
+UiListArgs* ui_list_args_new(void) {
+ UiListArgs *args = malloc(sizeof(UiListArgs));
+ memset(args, 0, sizeof(UiListArgs));
+ return args;
+}
+
+void ui_list_args_set_fill(UiListArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+void ui_list_args_set_hexpand(UiListArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+void ui_list_args_set_vexpand(UiListArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+void ui_list_args_set_hfill(UiListArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+void ui_list_args_set_vfill(UiListArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_list_args_set_colspan(UiListArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+void ui_list_args_set_rowspan(UiListArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+void ui_list_args_set_name(UiListArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+void ui_list_args_set_style_class(UiListArgs *args, const char *classname) {
+ args->style_class = classname;
+}
+
+void ui_list_args_set_varname(UiListArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_list_args_set_value(UiListArgs *args, UiList *value) {
+ args->list = value;
+}
+
+void ui_list_args_set_model(UiListArgs *args, UiModel *model) {
+ args->model = model;
+}
+
+void ui_list_args_set_static_elements(UiListArgs *args, char **strarray, size_t nelm) {
+ char **array = calloc(nelm, sizeof(char*));
+ for(int i=0;istatic_elements = array;
+ args->static_nelm = nelm;
+}
+
+void ui_list_args_set_getvalue_func(UiListArgs *args, ui_getvaluefunc getvalue) {
+ args->getvalue = getvalue;
+}
+
+void ui_list_args_set_getvalue_func2(UiListArgs *args, ui_getvaluefunc2 getvalue) {
+ args->getvalue2 = getvalue;
+}
+
+void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata) {
+ args->getvalue2data = userdata;
+}
+
+void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback) {
+ args->onactivate = callback;
+}
+
+void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata) {
+ args->onactivatedata = userdata;
+}
+
+void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback) {
+ args->onselection = callback;
+}
+
+void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata) {
+ args->onselectiondata = userdata;
+}
+
+void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback) {
+ args->ondragstart = callback;
+}
+
+void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata) {
+ args->ondragstartdata = userdata;
+}
+
+void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback) {
+ args->ondragcomplete = callback;
+}
+
+void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata) {
+ args->ondragcompletedata = userdata;
+}
+
+void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback) {
+ args->ondrop = callback;
+}
+
+void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata) {
+ args->ondropdata = userdata;
+}
+
+void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection) {
+ args->multiselection = multiselection;
+}
+
+void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder) {
+ args->contextmenu = menubuilder;
+}
+
+void ui_list_args_set_groups(UiListArgs *args, int *groups) {
+ // TODO
+}
+
+void ui_list_args_free(UiListArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ if(args->static_elements) {
+ for(int i=0;istatic_nelm;i++) {
+ free(args->static_elements[i]);
+ }
+ free(args->static_elements);
+ }
+ free(args);
+}
+
+
+
+/* ---------------------- SurceList ------------------------------------- */
+
+UiSourceListArgs* ui_sourcelist_args_new(void) {
+ UiSourceListArgs *args = malloc(sizeof(UiSourceListArgs));
+ memset(args, 0, sizeof(UiSourceListArgs));
+ return args;
+}
+
+
+void ui_sourcelist_args_set_fill(UiSourceListArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_sourcelist_args_set_hexpand(UiSourceListArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_sourcelist_args_set_vexpand(UiSourceListArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_sourcelist_args_set_hfill(UiSourceListArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_sourcelist_args_set_vfill(UiSourceListArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_sourcelist_args_set_rowspan(UiSourceListArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_sourcelist_args_set_name(UiSourceListArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_sourcelist_args_set_style_class(UiSourceListArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+UIEXPORT void ui_sourcelist_args_set_static_sublists(UiSourceListArgs *args, UiSubList *sublists, size_t numsublists) {
+ args->sublists = calloc(numsublists, sizeof(UiSubList));
+ memcpy(args->sublists, sublists, numsublists * sizeof(UiSubList));
+ args->numsublists = numsublists;
+}
+
+void ui_sourcelist_args_set_varname(UiSourceListArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+
+void ui_sourcelist_args_set_dynamic_sublists(UiSourceListArgs *args, UiList *value) {
+ args->dynamic_sublist = value;
+}
+
+
+void ui_sourcelist_args_set_getvalue_func(UiSourceListArgs *args, ui_sublist_getvalue_func getvalue) {
+ args->getvalue = getvalue;
+}
+
+void ui_sourcelist_args_set_getvalue_userdata(UiSourceListArgs *args, void *userdata) {
+ args->getvaluedata = userdata;
+}
+
+void ui_sourcelist_args_set_onactivate(UiSourceListArgs *args, ui_callback callback) {
+ args->onactivate = callback;
+}
+
+
+void ui_sourcelist_args_set_onactivatedata(UiSourceListArgs *args, void *userdata) {
+ args->onactivatedata = userdata;
+}
+
+
+void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback callback) {
+ args->onbuttonclick = callback;
+
+}
+
+
+void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata) {
+ args->onbuttonclickdata = userdata;
+}
+
+
+void ui_sourcelist_args_free(UiSourceListArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free((void*)args->sublists);
+ free(args);
+}
+
+
+/* ------------------------- UiTextAreaArgs ----------------------------*/
+
+UiTextAreaArgs* ui_textarea_args_new(void) {
+ UiTextAreaArgs *args = malloc(sizeof(UiTextAreaArgs));
+ memset(args, 0, sizeof(UiTextAreaArgs));
+ return args;
+}
+
+
+void ui_textarea_args_set_fill(UiTextAreaArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_textarea_args_set_hexpand(UiTextAreaArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_textarea_args_set_vexpand(UiTextAreaArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_textarea_args_set_hfill(UiTextAreaArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_textarea_args_set_vfill(UiTextAreaArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_textarea_args_set_rowspan(UiTextAreaArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback){
+ args->onchange = callback;
+}
+
+
+void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata){
+ args->onchangedata = onchangedata;
+}
+
+void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value) {
+ args->value = value;
+}
+
+void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *groups){
+ // TODO
+}
+
+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(args);
+}
+
+
+
+/* ------------------------- UiTextFieldArgs ----------------------------*/
+
+UiTextFieldArgs* ui_textfield_args_new(void) {
+ UiTextFieldArgs *args = malloc(sizeof(UiTextFieldArgs));
+ memset(args, 0, sizeof(UiTextFieldArgs));
+ return args;
+}
+
+
+void ui_textfield_args_set_fill(UiTextFieldArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_textfield_args_set_hexpand(UiTextFieldArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_textfield_args_set_vexpand(UiTextFieldArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_textfield_args_set_hfill(UiTextFieldArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_textfield_args_set_vfill(UiTextFieldArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_textfield_args_set_rowspan(UiTextFieldArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_textfield_args_set_name(UiTextFieldArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_textfield_args_set_style_class(UiTextFieldArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback callback){
+ args->onchange = callback;
+}
+
+
+void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata){
+ args->onchangedata = onchangedata;
+}
+
+void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback){
+ args->onactivate = callback;
+}
+
+
+void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata){
+ args->onactivatedata = onactivatedata;
+}
+
+void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value) {
+ args->value = value;
+}
+
+void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *groups){
+ // TODO
+}
+
+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(args);
+}
+
+
+/* ------------------------- UiWebviewArgs ----------------------------*/
+
+UiWebviewArgs* ui_webview_args_new(void) {
+ UiWebviewArgs *args = malloc(sizeof(UiWebviewArgs));
+ memset(args, 0, sizeof(UiWebviewArgs));
+ return args;
+}
+
+
+void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_webview_args_set_hexpand(UiWebviewArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_webview_args_set_vexpand(UiWebviewArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_webview_args_set_hfill(UiWebviewArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_webview_args_set_vfill(UiWebviewArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_webview_args_set_rowspan(UiWebviewArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_webview_args_set_name(UiWebviewArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value) {
+ args->value = value;
+}
+
+void ui_webview_args_set_groups(UiWebviewArgs *args, int *groups){
+ // TODO
+}
+
+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(args);
+}
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/args.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/args.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,405 @@
+/*
+ * 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_ARGS_H
+#define UIC_ARGS_H
+
+#include "../ui/window.h"
+#include "../ui/container.h"
+#include "../ui/display.h"
+#include "../ui/button.h"
+#include "../ui/menu.h"
+#include "../ui/toolbar.h"
+#include "../ui/tree.h"
+#include "../ui/text.h"
+#include "../ui/webview.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UIEXPORT UiDialogArgs* ui_dialog_args_new(void);
+UIEXPORT void ui_dialog_args_set_title(UiDialogArgs *args, const char *title);
+UIEXPORT void ui_dialog_args_set_content(UiDialogArgs *args, const char *str);
+UIEXPORT void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value);
+UIEXPORT void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input);
+UIEXPORT void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password);
+UIEXPORT void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb);
+UIEXPORT void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata);
+UIEXPORT void ui_dialog_args_free(UiDialogArgs *args);
+
+UIEXPORT UiDialogWindowArgs* ui_dialogwindow_args_new(void);
+UIEXPORT void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button);
+UIEXPORT void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width);
+UIEXPORT void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height);
+UIEXPORT void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb);
+UIEXPORT void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata);
+UIEXPORT void ui_dialogwindow_args_free(UiDialogWindowArgs *args);
+
+UIEXPORT UiMenuItemArgs* ui_menuitem_args_new(void);
+UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label);
+UIEXPORT void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid);
+UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon);
+UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback);
+UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata);
+UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args);
+
+UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void);
+UIEXPORT void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *label);
+UIEXPORT void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid);
+UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname);
+UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback);
+UIEXPORT void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args);
+
+UIEXPORT UiMenuItemListArgs* ui_menuitemlist_args_new(void);
+UIEXPORT void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname);
+UIEXPORT void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func);
+UIEXPORT void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback);
+UIEXPORT void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data);
+UIEXPORT void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value);
+UIEXPORT void ui_menuitemlist_args_free(UiMenuItemListArgs *args);
+
+UIEXPORT UiToolbarItemArgs* ui_toolbar_item_args_new(void);
+UIEXPORT void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon);
+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 *groups);
+UIEXPORT void ui_toolbar_item_args_free(UiToolbarItemArgs *args);
+
+UIEXPORT UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void);
+UIEXPORT void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label);
+UIEXPORT void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon);
+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 *groups);
+UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
+
+UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
+UIEXPORT void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label);
+UIEXPORT void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid);
+UIEXPORT void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args);
+
+UIEXPORT UiContainerArgs* ui_container_args_new(void);
+UIEXPORT void ui_container_args_set_fill(UiContainerArgs *args, UiBool fill);
+UIEXPORT void ui_container_args_set_hexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_vexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_hfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_vfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_override_defaults(UiContainerArgs *args, UiBool 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);
+UIEXPORT void ui_container_args_set_def_vexpand(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_def_hfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_def_vfill(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_name(UiContainerArgs *args, const char *name);
+UIEXPORT void ui_container_args_set_style_class(UiContainerArgs *args, const char *classname);
+UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_spacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_columnspacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_rowspacing(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_free(UiContainerArgs *args);
+
+
+UIEXPORT UiFrameArgs* ui_frame_args_new(void);
+UIEXPORT void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill);
+UIEXPORT void ui_frame_args_set_hexpand(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_vexpand(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_hfill(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_vfill(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan);
+UIEXPORT void ui_frame_args_set_rowspan(UiFrameArgs *args, int rowspan);
+UIEXPORT void ui_frame_args_set_name(UiFrameArgs *args, const char *name);
+UIEXPORT void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname);
+UIEXPORT void ui_frame_args_set_margin(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_spacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_expanded(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_label(UiFrameArgs *args, const char *label);
+UIEXPORT void ui_frame_args_free(UiFrameArgs *args);
+
+UIEXPORT UiSidebarArgs* ui_sidebar_args_new(void);
+UIEXPORT void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name);
+UIEXPORT void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname);
+UIEXPORT void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_free(UiSidebarArgs *args);
+
+UIEXPORT UiSplitPaneArgs* ui_splitpane_args_new(void);
+UIEXPORT void ui_splitpane_args_set_fill(UiSplitPaneArgs *args, UiBool fill);
+UIEXPORT void ui_splitpane_args_set_hexpand(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan);
+UIEXPORT void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan);
+UIEXPORT void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name);
+UIEXPORT void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname);
+UIEXPORT void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_columnspacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_rowspacing(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos);
+UIEXPORT void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname);
+UIEXPORT void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value);
+UIEXPORT void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max);
+UIEXPORT void ui_splitpane_args_free(UiSplitPaneArgs *args);
+
+UIEXPORT UiLabelArgs* ui_label_args_new(void);
+UIEXPORT void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill);
+UIEXPORT void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_colspan(UiLabelArgs *args, int colspan);
+UIEXPORT void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan);
+UIEXPORT void ui_label_args_set_name(UiLabelArgs *args, const char *name);
+UIEXPORT void ui_label_args_set_style_class(UiLabelArgs *args, const char *classname);
+UIEXPORT void ui_label_args_set_label(UiLabelArgs *args, const char *label);
+UIEXPORT void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align);
+UIEXPORT void ui_label_args_set_style(UiLabelArgs *args, UiLabelStyle style);
+UIEXPORT void ui_label_args_set_value(UiLabelArgs *args, UiString *value);
+UIEXPORT void ui_label_args_set_varname(UiLabelArgs *args, const char *varname);
+UIEXPORT void ui_label_args_free(UiLabelArgs *args);
+
+UIEXPORT UiProgressbarArgs* ui_progressbar_args_new(void);
+UIEXPORT void ui_progressbar_args_set_fill(UiProgressbarArgs *args, UiBool fill);
+UIEXPORT void ui_progressbar_args_set_hexpand(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_vexpand(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_hfill(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_vfill(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan);
+UIEXPORT void ui_progressbar_args_set_rowspan(UiProgressbarArgs *args, int rowspan);
+UIEXPORT void ui_progressbar_args_set_name(UiProgressbarArgs *args, const char *name);
+UIEXPORT void ui_progressbar_args_set_style_class(UiProgressbarArgs *args, const char *classname);
+UIEXPORT void ui_progressbar_args_set_min(UiProgressbarArgs *args, double min);
+UIEXPORT void ui_progressbar_args_set_max(UiProgressbarArgs *args, double max);
+UIEXPORT void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value);
+UIEXPORT void ui_progressbar_args_set_varname(UiProgressbarArgs *args, const char *varname);
+UIEXPORT void ui_progressbar_args_free(UiProgressbarArgs *args);
+
+UIEXPORT UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void);
+UIEXPORT void ui_progress_spinner_args_set_fill(UiProgressbarSpinnerArgs *args, UiBool fill);
+UIEXPORT void ui_progress_spinner_args_set_hexpand(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_vexpand(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_hfill(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_vfill(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan);
+UIEXPORT void ui_progress_spinner_args_set_rowspan(UiProgressbarSpinnerArgs *args, int rowspan);
+UIEXPORT void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, const char *name);
+UIEXPORT void ui_progress_spinner_args_set_style_class(UiProgressbarSpinnerArgs *args, const char *classname);
+UIEXPORT void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiInteger *value);
+UIEXPORT void ui_progress_spinner_args_set_varname(UiProgressbarSpinnerArgs *args, const char *varname);
+UIEXPORT void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args);
+
+UIEXPORT UiButtonArgs* ui_button_args_new(void);
+UIEXPORT void ui_button_args_set_fill(UiButtonArgs *args, UiBool fill);
+UIEXPORT void ui_button_args_set_hexpand(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_colspan(UiButtonArgs *args, int colspan);
+UIEXPORT void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan);
+UIEXPORT void ui_button_args_set_name(UiButtonArgs *args, const char *name);
+UIEXPORT void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname);
+UIEXPORT void ui_button_args_set_label(UiButtonArgs *args, const char *label);
+UIEXPORT void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid);
+UIEXPORT void ui_button_args_set_icon(UiButtonArgs *args, const char *icon);
+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 *groups);
+UIEXPORT void ui_button_args_free(UiButtonArgs *args);
+
+UIEXPORT UiToggleArgs* ui_toggle_args_new(void);
+UIEXPORT void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill);
+UIEXPORT void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan);
+UIEXPORT void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan);
+UIEXPORT void ui_toggle_args_set_name(UiToggleArgs *args, const char *name);
+UIEXPORT void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname);
+UIEXPORT void ui_toggle_args_set_label(UiToggleArgs *args, const char *label);
+UIEXPORT void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid);
+UIEXPORT void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon);
+UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype);
+UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback);
+UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
+UIEXPORT void ui_toggle_args_set_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 *groups);
+UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
+
+UIEXPORT UiListArgs* ui_list_args_new(void);
+UIEXPORT void ui_list_args_set_fill(UiListArgs *args, UiBool fill);
+UIEXPORT void ui_list_args_set_hexpand(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_vexpand(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_hfill(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_vfill(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_colspan(UiListArgs *args, int colspan);
+UIEXPORT void ui_list_args_set_rowspan(UiListArgs *args, int rowspan);
+UIEXPORT void ui_list_args_set_name(UiListArgs *args, const char *name);
+UIEXPORT void ui_list_args_set_style_class(UiListArgs *args, const char *classname);
+UIEXPORT void ui_list_args_set_varname(UiListArgs *args, const char *varname);
+UIEXPORT void ui_list_args_set_value(UiListArgs *args, UiList *value);
+UIEXPORT void ui_list_args_set_model(UiListArgs *args, UiModel *model);
+UIEXPORT void ui_list_args_set_static_elements(UiListArgs *args, char **strarray, size_t nelm);
+UIEXPORT void ui_list_args_set_getvalue_func(UiListArgs *args, ui_getvaluefunc getvalue);
+UIEXPORT void ui_list_args_set_getvalue_func2(UiListArgs *args, ui_getvaluefunc2 getvalue);
+UIEXPORT void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback);
+UIEXPORT void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_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 *groups);
+UIEXPORT void ui_list_args_free(UiListArgs *args);
+
+UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void);
+UIEXPORT void ui_sourcelist_args_set_fill(UiSourceListArgs *args, UiBool fill);
+UIEXPORT void ui_sourcelist_args_set_hexpand(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_vexpand(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_hfill(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_vfill(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan);
+UIEXPORT void ui_sourcelist_args_set_rowspan(UiSourceListArgs *args, int rowspan);
+UIEXPORT void ui_sourcelist_args_set_name(UiSourceListArgs *args, const char *name);
+UIEXPORT void ui_sourcelist_args_set_style_class(UiSourceListArgs *args, const char *classname);
+UIEXPORT void ui_sourcelist_args_set_static_sublists(UiSourceListArgs *args, UiSubList *sublists, size_t numsublists);
+UIEXPORT void ui_sourcelist_args_set_varname(UiSourceListArgs *args, const char *varname);
+UIEXPORT void ui_sourcelist_args_set_dynamic_sublists(UiSourceListArgs *args, UiList *value);
+UIEXPORT void ui_sourcelist_args_set_getvalue_func(UiSourceListArgs *args, ui_sublist_getvalue_func getvalue);
+UIEXPORT void ui_sourcelist_args_set_getvalue_userdata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_set_onactivate(UiSourceListArgs *args, ui_callback callback);
+UIEXPORT void ui_sourcelist_args_set_onactivatedata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback callback);
+UIEXPORT void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_free(UiSourceListArgs *args);
+
+UIEXPORT UiTextAreaArgs* ui_textarea_args_new(void);
+UIEXPORT void ui_textarea_args_set_fill(UiTextAreaArgs *args, UiBool fill);
+UIEXPORT void ui_textarea_args_set_hexpand(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_vexpand(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_hfill(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_vfill(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan);
+UIEXPORT void ui_textarea_args_set_rowspan(UiTextAreaArgs *args, int rowspan);
+UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name);
+UIEXPORT void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname);
+UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback);
+UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
+UIEXPORT void ui_textarea_args_set_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 *groups);
+UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args);
+
+UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void);
+UIEXPORT void ui_textfield_args_set_fill(UiTextFieldArgs *args, UiBool fill);
+UIEXPORT void ui_textfield_args_set_hexpand(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_vexpand(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_hfill(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_vfill(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan);
+UIEXPORT void ui_textfield_args_set_rowspan(UiTextFieldArgs *args, int rowspan);
+UIEXPORT void ui_textfield_args_set_name(UiTextFieldArgs *args, const char *name);
+UIEXPORT void ui_textfield_args_set_style_class(UiTextFieldArgs *args, const char *classname);
+UIEXPORT void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback callback);
+UIEXPORT void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata);
+UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback);
+UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
+UIEXPORT void ui_textfield_args_set_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 *groups);
+UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args);
+
+UIEXPORT UiWebviewArgs* ui_webview_args_new(void);
+UIEXPORT void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill);
+UIEXPORT void ui_webview_args_set_hexpand(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_vexpand(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_hfill(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_vfill(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan);
+UIEXPORT void ui_webview_args_set_rowspan(UiWebviewArgs *args, int rowspan);
+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 *groups);
+UIEXPORT void ui_webview_args_free(UiWebviewArgs *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_ARGS_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/context.c
--- a/ui/common/context.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/context.c Sun Jul 20 22:04:39 2025 +0200
@@ -58,6 +58,7 @@
memset(ctx, 0, sizeof(UiContext));
ctx->mp = mp;
ctx->allocator = mp->allocator;
+ ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16);
ctx->obj = toplevel;
ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16);
@@ -66,7 +67,7 @@
ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
ctx->attach_document = uic_context_attach_document;
- ctx->detach_document2 = uic_context_detach_document2;
+ ctx->detach_document2 = uic_context_detach_document;
#if UI_GTK2 || UI_GTK3
if(toplevel && toplevel->widget) {
@@ -82,6 +83,13 @@
return ctx->parent ? uic_root_context(ctx->parent) : ctx;
}
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) {
+ UiDestroyHandler handler;
+ handler.destructor = func;
+ handler.data = data;
+ cxListAdd(ctx->destroy_handler, &handler);
+}
+
void uic_context_prepare_close(UiContext *ctx) {
cxListClear(ctx->groups);
cxListClear(ctx->group_widgets);
@@ -120,11 +128,12 @@
CxMapIterator mi = cxMapIterator(ctx->vars);
cx_foreach(CxMapEntry*, entry, mi) {
UiVar *var = entry->value;
- if(var->from && var->from_ctx && var->from_ctx != ctx) {
+ // var->from && var->from_ctx && var->from_ctx != ctx
+ if(var->from) {
uic_save_var2(var);
uic_copy_binding(var, var->from, FALSE);
- cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from);
- var->from_ctx = ctx;
+ cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from);
+ var->from = NULL;
}
}
@@ -137,7 +146,7 @@
}
}
-void uic_context_detach_document2(UiContext *ctx, void *document) {
+void uic_context_detach_document(UiContext *ctx, void *document) {
// find the document in the documents list
size_t docIndex = cxListFind(ctx->documents, document);
if(!cxListIndexValid(ctx->documents, docIndex)) {
@@ -209,6 +218,7 @@
var = ui_malloc(ctx, sizeof(UiVar));
var->type = type;
var->value = uic_create_value(ctx, type);
+ var->original_value = NULL;
var->from = NULL;
var->from_ctx = ctx;
@@ -227,6 +237,7 @@
var->from = NULL;
var->from_ctx = ctx;
var->value = value;
+ var->original_value = NULL;
var->type = UI_VAR_SPECIAL;
return var;
}
@@ -286,10 +297,19 @@
}
void *fromvalue = from->value;
+ void *tovalue = to->value;
// update var
if(copytodoc) {
- to->from = from;
- to->from_ctx = from->from_ctx;
+ to->from = from; // from which UiVar are the bindings copied
+ from->original_value = fromvalue; // save original value otherwise it would be lost
+ // widgets store a reference to the UiVar with their value
+ // the UiVar object must be updated to contain the current value object
+ from->value = tovalue;
+ } else {
+ if(to->original_value) {
+ to->value = to->original_value;
+ tovalue = to->value;
+ }
}
ui_setop_enable(TRUE);
@@ -301,7 +321,7 @@
case UI_VAR_SPECIAL: break;
case UI_VAR_INTEGER: {
UiInteger *f = fromvalue;
- UiInteger *t = to->value;
+ UiInteger *t = tovalue;
if(!f->obj) break;
uic_int_copy(f, t);
t->set(t, t->value);
@@ -309,7 +329,7 @@
}
case UI_VAR_DOUBLE: {
UiDouble *f = fromvalue;
- UiDouble *t = to->value;
+ UiDouble *t = tovalue;
if(!f->obj) break;
uic_double_copy(f, t);
t->set(t, t->value);
@@ -317,48 +337,32 @@
}
case UI_VAR_STRING: {
UiString *f = fromvalue;
- UiString *t = to->value;
+ UiString *t = tovalue;
if(!f->obj) break;
uic_string_copy(f, t);
char *tvalue = t->value.ptr ? t->value.ptr : "";
+ char *fvalue = f->value.ptr ? f->value.ptr : "";
t->set(t, tvalue);
break;
}
case UI_VAR_TEXT: {
UiText *f = fromvalue;
- UiText *t = to->value;
+ UiText *t = tovalue;
if(!f->obj) break;
uic_text_copy(f, t);
t->restore(t);
break;
}
- case UI_VAR_LIST: {
- // TODO: not sure how correct this is
-
- UiList *f = from->value;
- UiList *t = to->value;
- if (f->obj) {
- t->obj = f->obj;
- t->update = f->update;
- t->getselection = f->getselection;
- t->setselection = f->setselection;
- }
-
- UiVar tmp = *from;
- *from = *to;
- *to = tmp;
-
- UiList* t2 = to->value;
- if(t->update) {
- t->update(t, -1);
- }
- ui_notify(t2->observers, NULL); // TODO: why not t?
-
+ case UI_VAR_LIST: {
+ UiList *f = fromvalue;
+ UiList *t = tovalue;
+ uic_list_copy(f, t);
+ ui_list_update(t);
break;
}
case UI_VAR_RANGE: {
UiRange *f = fromvalue;
- UiRange *t = to->value;
+ UiRange *t = tovalue;
if(!f->obj) break;
uic_range_copy(f, t);
t->setextent(t, t->extent);
@@ -368,7 +372,7 @@
}
case UI_VAR_GENERIC: {
UiGeneric *f = fromvalue;
- UiGeneric *t = to->value;
+ UiGeneric *t = tovalue;
if(!f->obj) break;
uic_generic_copy(f, t);
t->set(t, t->value, t->type);
@@ -405,7 +409,7 @@
}
}
-void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) {
+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
@@ -463,8 +467,8 @@
uic_context_attach_document(ctx, document);
}
-void ui_detach_document2(UiContext *ctx, void *document) {
- uic_context_detach_document2(ctx, document);
+void ui_detach_document(UiContext *ctx, void *document) {
+ uic_context_detach_document(ctx, document);
}
void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
@@ -472,10 +476,18 @@
ctx->close_data = udata;
}
-UIEXPORT void ui_context_destroy(UiContext *ctx) {
+void ui_context_destroy(UiContext *ctx) {
+ CxIterator i = cxListIterator(ctx->destroy_handler);
+ cx_foreach(UiDestroyHandler *, h, i) {
+ h->destructor(h->data);
+ }
cxMempoolFree(ctx->mp);
}
+UiContext* ui_context_parent(UiContext *ctx) {
+ return ctx->parent;
+}
+
void ui_set_group(UiContext *ctx, int group) {
if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/context.h
--- a/ui/common/context.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/context.h Sun Jul 20 22:04:39 2025 +0200
@@ -40,10 +40,11 @@
extern "C" {
#endif
-typedef struct UiVar UiVar;
-typedef struct UiListPtr UiListPtr;
-typedef struct UiListVar UiListVar;
-typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiVar UiVar;
+typedef struct UiListPtr UiListPtr;
+typedef struct UiListVar UiListVar;
+typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiDestroyHandler UiDestroyHandler;
typedef enum UiVarType {
UI_VAR_SPECIAL = 0,
@@ -61,6 +62,7 @@
UiObject *obj;
CxMempool *mp;
const CxAllocator *allocator;
+ CxList *destroy_handler;
void *document;
CxList *documents;
@@ -93,8 +95,9 @@
// UiVar replacement, rename it to UiVar when finished
struct UiVar {
void *value;
+ void *original_value;
UiVarType type;
- UiVar *from;
+ UiVar *from;
UiContext *from_ctx;
};
@@ -105,18 +108,24 @@
int numgroups;
};
+struct UiDestroyHandler {
+ cx_destructor_func destructor;
+ void *data;
+};
+
void uic_init_global_context(void);
UiContext* uic_context(UiObject *toplevel, CxMempool *mp);
UiContext* uic_root_context(UiContext *ctx);
-void uic_context_set_document(UiContext *ctx, void *document); // deprecated
-void uic_context_detach_document(UiContext *ctx); // deprecated
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
void uic_context_prepare_close(UiContext *ctx);
void uic_context_attach_document(UiContext *ctx, void *document);
-void uic_context_detach_document2(UiContext *ctx, void *document);
+void uic_context_detach_document(UiContext *ctx, void *document);
+void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
+void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); // TODO
void uic_context_detach_all(UiContext *ctx);
UiVar* uic_get_var(UiContext *ctx, const char *name);
@@ -130,7 +139,7 @@
void uic_save_var2(UiVar *var);
void uic_unbind_var(UiVar *var);
-void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value);
+void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
void uic_remove_bound_var(UiContext *ctx, UiVar *var);
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/document.c
--- a/ui/common/document.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/document.c Sun Jul 20 22:04:39 2025 +0200
@@ -44,46 +44,8 @@
}
}
-void ui_set_document(UiObject *obj, void *document) {
- uic_context_detach_all(obj->ctx);
- obj->ctx->attach_document(obj->ctx, document);
-}
-
-void ui_detach_document(UiObject *obj) {
- uic_context_detach_all(obj->ctx);
-}
-
-void* ui_get_document(UiObject *obj) {
- return obj->ctx->document;
-}
-
-void ui_set_subdocument(void *document, void *sub) {
- UiContext *ctx = ui_document_context(document);
- if(!ctx) {
- fprintf(stderr, "UI Error: pointer is not a document\n");
- }
- // TODO
-}
-
-void ui_detach_subdocument(void *document, void *sub) {
- UiContext *ctx = ui_document_context(document);
- if(!ctx) {
- fprintf(stderr, "UI Error: pointer is not a document\n");
- }
- // TODO
-}
-
-void* ui_get_subdocument(void *document) {
- UiContext *ctx = ui_document_context(document);
- if(!ctx) {
- fprintf(stderr, "UI Error: pointer is not a document\n");
- }
- // TODO
- return NULL;
-}
-
void* ui_document_new(size_t size) {
- CxMempool *mp = cxMempoolCreate(256, NULL);
+ CxMempool *mp = cxMempoolCreateSimple(256);
const CxAllocator *a = mp->allocator;
UiContext *ctx = uic_context(NULL, mp);
@@ -100,6 +62,7 @@
ev.document = doc;
ev.obj = NULL;
ev.eventdata = NULL;
+ ev.eventdatatype = 0;
ev.intval = 0;
if(ctx->close_callback) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/menu.c
--- a/ui/common/menu.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/menu.c Sun Jul 20 22:04:39 2025 +0200
@@ -125,19 +125,19 @@
-void ui_menuitem_create(UiMenuItemArgs args) {
+void ui_menuitem_create(UiMenuItemArgs *args) {
UiMenuItem* item = malloc(sizeof(UiMenuItem));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_ITEM;
- item->label = nl_strdup(args.label);
- item->stockid = nl_strdup(args.stockid);
- item->icon = nl_strdup(args.icon);
- item->userdata = args.onclickdata;
- item->callback = args.onclick;
- item->groups = uic_copy_groups(args.groups, &item->ngroups);
+ item->label = nl_strdup(args->label);
+ item->stockid = nl_strdup(args->stockid);
+ item->icon = nl_strdup(args->icon);
+ item->userdata = args->onclickdata;
+ item->callback = args->onclick;
+ item->groups = uic_copy_groups(args->groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
@@ -152,79 +152,79 @@
add_item((UiMenuItemI*)item);
}
-void ui_menu_toggleitem_create(UiMenuToggleItemArgs args) {
+void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args) {
UiMenuCheckItem *item = malloc(sizeof(UiMenuCheckItem));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_CHECK_ITEM;
- item->label = nl_strdup(args.label);
- item->stockid = nl_strdup(args.stockid);
- item->icon = nl_strdup(args.icon);
- item->varname = nl_strdup(args.varname);
- item->userdata = args.onchangedata;
- item->callback = args.onchange;
- item->groups = uic_copy_groups(args.groups, &item->ngroups);
+ item->label = nl_strdup(args->label);
+ item->stockid = nl_strdup(args->stockid);
+ item->icon = nl_strdup(args->icon);
+ item->varname = nl_strdup(args->varname);
+ item->userdata = args->onchangedata;
+ item->callback = args->onchange;
+ item->groups = uic_copy_groups(args->groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
-void ui_menu_radioitem_create(UiMenuToggleItemArgs args) {
+void ui_menu_radioitem_create(UiMenuToggleItemArgs *args) {
UiMenuCheckItem* item = malloc(sizeof(UiMenuCheckItem));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_RADIO_ITEM;
- item->label = nl_strdup(args.label);
- item->stockid = nl_strdup(args.stockid);
- item->icon = nl_strdup(args.icon);
- item->varname = nl_strdup(args.varname);
- item->userdata = args.onchangedata;
- item->callback = args.onchange;
- item->groups = uic_copy_groups(args.groups, &item->ngroups);
+ item->label = nl_strdup(args->label);
+ item->stockid = nl_strdup(args->stockid);
+ item->icon = nl_strdup(args->icon);
+ item->varname = nl_strdup(args->varname);
+ item->userdata = args->onchangedata;
+ item->callback = args->onchange;
+ item->groups = uic_copy_groups(args->groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
-void ui_menu_itemlist_create(UiMenuItemListArgs args) {
+void ui_menu_itemlist_create(UiMenuItemListArgs *args) {
UiMenuItemList*item = malloc(sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_ITEM_LIST;
- item->getvalue = args.getvalue;
- item->callback = args.onselect;
- item->userdata = args.onselectdata;
- item->varname = nl_strdup(args.varname);
- item->addseparator = args.addseparator;
+ item->getvalue = args->getvalue;
+ item->callback = args->onselect;
+ item->userdata = args->onselectdata;
+ item->varname = nl_strdup(args->varname);
+ item->addseparator = args->addseparator;
add_item((UiMenuItemI*)item);
}
-void ui_menu_checkitemlist_create(UiMenuItemListArgs args) {
+void ui_menu_checkitemlist_create(UiMenuItemListArgs *args) {
UiMenuItemList* item = malloc(sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_CHECKITEM_LIST;
- item->callback = args.onselect;
- item->userdata = args.onselectdata;
- item->varname = nl_strdup(args.varname);
+ item->callback = args->onselect;
+ item->userdata = args->onselectdata;
+ item->varname = nl_strdup(args->varname);
add_item((UiMenuItemI*)item);
}
-void ui_menu_radioitemlist_create(UiMenuItemListArgs args) {
+void ui_menu_radioitemlist_create(UiMenuItemListArgs *args) {
UiMenuItemList* item = malloc(sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev = NULL;
item->item.next = NULL;
item->item.type = UI_MENU_RADIOITEM_LIST;
- item->callback = args.onselect;
- item->userdata = args.onselectdata;
- item->varname = nl_strdup(args.varname);
+ item->callback = args->onselect;
+ item->userdata = args->onselectdata;
+ item->varname = nl_strdup(args->varname);
add_item((UiMenuItemI*)item);
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/object.c
--- a/ui/common/object.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/object.c Sun Jul 20 22:04:39 2025 +0200
@@ -32,8 +32,48 @@
#include "object.h"
#include "context.h"
+#include
+
#include "../ui/container.h"
+static CxList *creation_callbacks;
+static CxList *destruction_callbacks;
+
+typedef struct objcallback {
+ ui_object_callback func;
+ void *userdata;
+} objcallback;
+
+void ui_register_object_creation_callback(ui_object_callback func, void *userdata) {
+ if(!creation_callbacks) {
+ creation_callbacks = cxLinkedListCreateSimple(sizeof(objcallback));
+ }
+ objcallback cb = { func, userdata };
+ cxListAdd(creation_callbacks, &cb);
+}
+
+void ui_register_object_destruction_callback(ui_object_callback func, void *userdata) {
+ if(!destruction_callbacks) {
+ destruction_callbacks = cxLinkedListCreateSimple(sizeof(objcallback));
+ }
+ objcallback cb = { func, userdata };
+ cxListAdd(destruction_callbacks, &cb);
+}
+
+void uic_object_created(UiObject *obj) {
+ CxIterator i = cxListIterator(creation_callbacks);
+ cx_foreach(objcallback *, cb, i) {
+ cb->func(obj, cb->userdata);
+ }
+}
+
+void uic_object_destroyed(UiObject *obj) {
+ CxIterator i = cxListIterator(destruction_callbacks);
+ cx_foreach(objcallback *, cb, i) {
+ cb->func(obj, cb->userdata);
+ }
+}
+
void ui_end(UiObject *obj) {
if(!obj->next) {
return;
@@ -84,12 +124,22 @@
ev.document = obj->ctx->document;
ev.obj = obj;
ev.eventdata = NULL;
+ ev.eventdatatype = 0;
ev.intval = 0;
obj->ctx->close_callback(&ev, obj->ctx->close_data);
}
+ uic_object_destroyed(obj);
cxMempoolFree(obj->ctx->mp);
}
+UiObject* uic_object_new_toplevel(void) {
+ CxMempool *mp = cxMempoolCreateSimple(256);
+ UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+ obj->ctx = uic_context(obj, mp);
+ uic_object_created(obj);
+ return obj;
+}
+
UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget) {
return uic_ctx_object_new(toplevel->ctx, widget);
}
@@ -98,7 +148,7 @@
UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
newobj->ctx = ctx;
newobj->widget = widget;
-
+ uic_object_created(newobj);
return newobj;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/object.h
--- a/ui/common/object.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/object.h Sun Jul 20 22:04:39 2025 +0200
@@ -35,8 +35,17 @@
extern "C" {
#endif
+typedef void (*ui_object_callback)(UiObject *obj, void *userdata);
+
+void ui_register_object_creation_callback(ui_object_callback func, void *userdata);
+void ui_register_object_destruction_callback(ui_object_callback func, void *userdata);
+
+void uic_object_created(UiObject *obj);
+void uic_object_destroyed(UiObject *obj);
+
void uic_object_destroy(UiObject *obj);
+UiObject* uic_object_new_toplevel(void);
UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget);
UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
void uic_obj_add(UiObject *toplevel, UiObject *ctobj);
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/objs.mk
--- a/ui/common/objs.mk Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/objs.mk Sun Jul 20 22:04:39 2025 +0200
@@ -33,13 +33,14 @@
COMMON_OBJ += document$(OBJ_EXT)
COMMON_OBJ += object$(OBJ_EXT)
COMMON_OBJ += types$(OBJ_EXT)
-COMMON_OBJ += menu$(OBJ_EXT)
COMMON_OBJ += properties$(OBJ_EXT)
COMMON_OBJ += menu$(OBJ_EXT)
COMMON_OBJ += toolbar$(OBJ_EXT)
COMMON_OBJ += ucx_properties$(OBJ_EXT)
COMMON_OBJ += threadpool$(OBJ_EXT)
COMMON_OBJ += condvar$(OBJ_EXT)
+COMMON_OBJ += args$(OBJ_EXT)
+COMMON_OBJ += wrapper$(OBJ_EXT)
TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/properties.c
--- a/ui/common/properties.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/properties.c Sun Jul 20 22:04:39 2025 +0200
@@ -32,6 +32,10 @@
#include
#include
+#ifdef _WIN32
+#include
+#endif
+
#include "../ui/toolkit.h"
@@ -187,6 +191,11 @@
return ret;
}
+// public
+int ui_app_save_settings(void) {
+ return uic_store_app_properties();
+}
+
const char* ui_get_property(const char *name) {
return cxMapGet(application_properties, name);
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/threadpool.c
--- a/ui/common/threadpool.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/threadpool.c Sun Jul 20 22:04:39 2025 +0200
@@ -165,6 +165,7 @@
event.document = job->obj->ctx->document;
event.intval = 0;
event.eventdata = NULL;
+ event.eventdatatype = 0;
job->finish_callback(&event, job->finish_data);
free(job);
return 0;
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/toolbar.c
--- a/ui/common/toolbar.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/toolbar.c Sun Jul 20 22:04:39 2025 +0200
@@ -49,18 +49,18 @@
return str ? strdup(str) : NULL;
}
-static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs args, size_t *ngroups) {
+static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups) {
UiToolbarItemArgs newargs;
- newargs.label = nl_strdup(args.label);
- newargs.stockid = nl_strdup(args.stockid);
- newargs.icon = nl_strdup(args.icon);
- newargs.onclick = args.onclick;
- newargs.onclickdata = args.onclickdata;
- newargs.groups = uic_copy_groups(args.groups, ngroups);
+ newargs.label = nl_strdup(args->label);
+ newargs.stockid = nl_strdup(args->stockid);
+ newargs.icon = nl_strdup(args->icon);
+ newargs.onclick = args->onclick;
+ newargs.onclickdata = args->onclickdata;
+ newargs.groups = uic_copy_groups(args->groups, ngroups);
return newargs;
}
-void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args) {
+void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args) {
UiToolbarItem* item = malloc(sizeof(UiToolbarItem));
item->item.type = UI_TOOLBAR_ITEM;
item->args = itemargs_copy(args, &item->ngroups);
@@ -68,34 +68,34 @@
}
-static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs args, size_t *ngroups) {
+static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args, size_t *ngroups) {
UiToolbarToggleItemArgs newargs;
- newargs.label = nl_strdup(args.label);
- newargs.stockid = nl_strdup(args.stockid);
- newargs.icon = nl_strdup(args.icon);
- newargs.varname = nl_strdup(args.varname);
- newargs.onchange = args.onchange;
- newargs.onchangedata = args.onchangedata;
- newargs.groups = uic_copy_groups(args.groups, ngroups);
+ newargs.label = nl_strdup(args->label);
+ newargs.stockid = nl_strdup(args->stockid);
+ newargs.icon = nl_strdup(args->icon);
+ newargs.varname = nl_strdup(args->varname);
+ newargs.onchange = args->onchange;
+ newargs.onchangedata = args->onchangedata;
+ newargs.groups = uic_copy_groups(args->groups, ngroups);
return newargs;
}
-void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs args) {
+void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args) {
UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem));
item->item.type = UI_TOOLBAR_TOGGLEITEM;
item->args = toggleitemargs_copy(args, &item->ngroups);
cxMapPut(toolbar_items, name, item);
}
-static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs args) {
+static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args) {
UiToolbarMenuArgs newargs;
- newargs.label = nl_strdup(args.label);
- newargs.stockid = nl_strdup(args.stockid);
- newargs.icon = nl_strdup(args.icon);
+ newargs.label = nl_strdup(args->label);
+ newargs.stockid = nl_strdup(args->stockid);
+ newargs.icon = nl_strdup(args->icon);
return newargs;
}
-UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs args) {
+UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args) {
UiToolbarMenuItem* item = malloc(sizeof(UiToolbarMenuItem));
item->item.type = UI_TOOLBAR_MENU;
memset(&item->menu, 0, sizeof(UiMenu));
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/types.c
--- a/ui/common/types.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/types.c Sun Jul 20 22:04:39 2025 +0200
@@ -36,8 +36,10 @@
#include "../ui/tree.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;
UiObserver* ui_observer_new(ui_callback f, void *data) {
UiObserver *observer = malloc(sizeof(UiObserver));
@@ -75,6 +77,7 @@
evt.window = NULL;
evt.document = NULL;
evt.eventdata = data;
+ evt.eventdatatype = UI_EVENT_DATA_POINTER;
evt.intval = 0;
while(observer) {
@@ -94,20 +97,22 @@
/* --------------------------- UiList --------------------------- */
-UiList* ui_list_new(UiContext *ctx, char *name) {
- UiList *list = malloc(sizeof(UiList));
+void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
+ list->data = cxArrayListCreate(ctx->mp->allocator, NULL, CX_STORE_POINTERS, 32);
list->first = ui_list_first;
list->next = ui_list_next;
list->get = ui_list_get;
list->count = ui_list_count;
- list->observers = NULL;
-
- list->data = cxArrayListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS, 32);
- list->iter = NULL;
-
- list->update = NULL;
- list->getselection = NULL;
- list->obj = NULL;
+}
+
+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);
+}
+
+UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) {
+ UiList *list = cxMalloc(ctx->mp->allocator, sizeof(UiList));
+ memset(list, 0, sizeof(UiList));
+ listinit(ctx, list, userdata);
if(name) {
uic_reg_var(ctx, name, UI_VAR_LIST, list);
@@ -248,7 +253,7 @@
// types
// public functions
-UiInteger* ui_int_new(UiContext *ctx, char *name) {
+UiInteger* ui_int_new(UiContext *ctx, const char *name) {
UiInteger *i = ui_malloc(ctx, sizeof(UiInteger));
memset(i, 0, sizeof(UiInteger));
if(name) {
@@ -257,7 +262,7 @@
return i;
}
-UiDouble* ui_double_new(UiContext *ctx, char *name) {
+UiDouble* ui_double_new(UiContext *ctx, const char *name) {
UiDouble *d = ui_malloc(ctx, sizeof(UiDouble));
memset(d, 0, sizeof(UiDouble));
if(name) {
@@ -266,7 +271,7 @@
return d;
}
-UiString* ui_string_new(UiContext *ctx, char *name) {
+UiString* ui_string_new(UiContext *ctx, const char *name) {
UiString *s = ui_malloc(ctx, sizeof(UiString));
memset(s, 0, sizeof(UiString));
if(name) {
@@ -275,7 +280,7 @@
return s;
}
-UiText* ui_text_new(UiContext *ctx, char *name) {
+UiText* ui_text_new(UiContext *ctx, const char *name) {
UiText *t = ui_malloc(ctx, sizeof(UiText));
memset(t, 0, sizeof(UiText));
if(name) {
@@ -284,7 +289,7 @@
return t;
}
-UiRange* ui_range_new(UiContext *ctx, char *name) {
+UiRange* ui_range_new(UiContext *ctx, const char *name) {
UiRange *r = ui_malloc(ctx, sizeof(UiRange));
memset(r, 0, sizeof(UiRange));
if(name) {
@@ -293,7 +298,7 @@
return r;
}
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name) {
+UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
memset(g, 0, sizeof(UiGeneric));
if(name) {
@@ -404,6 +409,30 @@
}
}
+void ui_generic_set_image(UiGeneric *g, void *img) {
+ if(g->set) {
+ g->set(g, img, UI_IMAGE_OBJECT_TYPE);
+ } else {
+ if(g->value) {
+ ui_image_unref(g->value);
+ }
+ ui_image_ref(img);
+ g->value = img;
+ g->type = UI_IMAGE_OBJECT_TYPE;
+ }
+}
+
+void* ui_generic_get_image(UiGeneric *g) {
+ if(g->type) {
+ if(!strcmp(g->type, UI_IMAGE_OBJECT_TYPE)) {
+ return g->value;
+ } else {
+ return NULL;
+ }
+ }
+ return g->value;
+}
+
// private functions
void uic_int_copy(UiInteger *from, UiInteger *to) {
@@ -452,6 +481,8 @@
void uic_list_copy(UiList *from, UiList *to) {
to->update = from->update;
+ to->getselection = from->getselection;
+ to->setselection = from->setselection;
to->obj = from->obj;
}
@@ -634,3 +665,34 @@
int ui_get_setop(void) {
return ui_set_op;
}
+
+/* ---------------- List initializers and wrapper functions ---------------- */
+
+void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
+ default_list_init = func;
+ default_list_init_userdata = userdata;
+}
+
+void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
+ list->first = first;
+}
+
+void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list)) {
+ list->next = next;
+}
+
+void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i)) {
+ list->get = get;
+}
+
+void ui_list_class_set_count(UiList *list, int(*count)(UiList *list)) {
+ list->count = count;
+}
+
+void ui_list_class_set_data(UiList *list, void *data) {
+ list->data = data;
+}
+
+void ui_list_class_set_iter(UiList *list, void *iter) {
+ list->iter = iter;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/types.h
--- a/ui/common/types.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/common/types.h Sun Jul 20 22:04:39 2025 +0200
@@ -34,8 +34,9 @@
#ifdef __cplusplus
extern "C" {
#endif
-
-
+
+void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused);
+
void uic_int_copy(UiInteger *from, UiInteger *to);
void uic_double_copy(UiDouble *from, UiDouble *to);
void uic_string_copy(UiString *from, UiString *to);
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/wrapper.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/wrapper.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,220 @@
+/*
+ * 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 "wrapper.h"
+#include "types.h"
+#include
+#include
+
+/* ---------------------------- UiObject ---------------------------- */
+
+UiContext* ui_object_get_context(UiObject *obj) {
+ return obj->ctx;
+}
+
+void* ui_object_get_windowdata(UiObject *obj) {
+ return obj->window;
+}
+
+void ui_object_set_windowdata(UiObject *obj, void *windowdata) {
+ obj->window = windowdata;
+}
+
+
+/* ---------------------------- UiList ---------------------------- */
+
+void* ui_list_get_data(UiList *list) {
+ return list->data;
+}
+
+void ui_list_set_data(UiList *list, void *data) {
+ list->data = data;
+}
+
+void* ui_list_get_iter(UiList *list) {
+ return list->iter;
+}
+
+void ui_list_set_iter(UiList *list, void *iter) {
+ list->iter = iter;
+}
+
+
+/* ------------------------------ UiSublist ------------------------------ */
+
+UiSubList* ui_sublist_new(void) {
+ UiSubList *sublist = malloc(sizeof(UiSubList));
+ memset(sublist, 0, sizeof(UiSubList));
+ return sublist;
+}
+
+void ui_sublist_set_value(UiSubList *sublist, UiList *value) {
+ sublist->value = value;
+}
+
+void ui_sublist_set_varname(UiSubList *sublist, const char *varname) {
+ free((void*)sublist->varname);
+ sublist->varname = strdup(varname);
+}
+
+void ui_sublist_set_header(UiSubList *sublist, const char *header) {
+ free((void*)sublist->header);
+ sublist->header = strdup(header);
+}
+
+void ui_sublist_set_separator(UiSubList *sublist, UiBool separator) {
+ sublist->separator = separator;
+}
+
+void ui_sublist_set_userdata(UiSubList *sublist, void *userdata) {
+ sublist->userdata = userdata;
+}
+
+void ui_sublist_free(UiSubList *sublist) {
+ free((void*)sublist->varname);
+ free((void*)sublist->header);
+ free(sublist);
+}
+
+
+/* -------------------- Source list (UiList) -------------------- */
+
+UiList* ui_srclist_new(UiContext *ctx, const char *name) {
+ UiList *list = ui_list_new2(ctx, name, uic_ucx_list_init, NULL);
+ CxList *cxlist = list->data;
+ cxlist->collection.simple_destructor = (cx_destructor_func)ui_sublist_free;
+ return list;
+}
+
+void ui_srclist_add(UiList *list, UiSubList *item) {
+ ui_list_append(list, item);
+}
+
+void ui_srclist_insert(UiList *list, int index, UiSubList *item) {
+ CxList *cxlist = list->data;
+ cxListInsert(cxlist, index, item);
+}
+
+void ui_srclist_remove(UiList *list, int index) {
+ CxList *cxlist = list->data;
+ cxListRemove(cxlist, index);
+}
+
+void ui_srclist_clear(UiList *list) {
+ CxList *cxlist = list->data;
+ cxListClear(cxlist);
+}
+
+int ui_srclist_size(UiList *list) {
+ return ui_list_count(list);
+}
+
+
+/* ---------------------------- UiSubListEventData ---------------------------- */
+
+UiList* ui_sublist_event_get_list(UiSubListEventData *event) {
+ return event->list;
+}
+
+int ui_sublist_event_get_sublist_index(UiSubListEventData *event) {
+ return event->sublist_index;
+}
+
+int ui_sublist_event_get_row_index(UiSubListEventData *event) {
+ return event->row_index;
+}
+
+void* ui_sublist_event_get_row_data(UiSubListEventData *event) {
+ return event->row_data;
+}
+
+void* ui_sublist_event_get_sublist_userdata(UiSubListEventData *event) {
+ return event->sublist_userdata;
+}
+
+void* ui_sublist_event_get_event_data(UiSubListEventData *event) {
+ return event->event_data;
+}
+
+
+/* ---------------------------- UiEvent ---------------------------- */
+
+UiObject* ui_event_get_obj(UiEvent *event) {
+ return event->obj;
+}
+
+void* ui_event_get_document(UiEvent *event) {
+ return event->document;
+}
+
+void* ui_event_get_windowdata(UiEvent *event) {
+ return event->window;
+}
+
+void* ui_event_get_eventdata(UiEvent *event) {
+ return event->eventdata;
+}
+
+int ui_event_get_eventdatatype(UiEvent *event) {
+ return event->eventdatatype;
+}
+
+int ui_event_get_int(UiEvent *event) {
+ return event->intval;
+}
+
+int ui_event_get_set(UiEvent *event) {
+ return event->set;
+}
+
+
+/* ------------------------- SubListItem (public) ------------------------- */
+
+void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon) {
+ item->icon = icon ? strdup(icon) : NULL;
+}
+
+void ui_sublist_item_set_label(UiSubListItem *item, const char *label) {
+ item->label = label ? strdup(label) : NULL;
+}
+
+void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon) {
+ item->button_icon = button_icon ? strdup(button_icon) : NULL;
+}
+
+void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label) {
+ item->button_label = button_label ? strdup(button_label) : NULL;
+}
+
+void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge) {
+ item->badge = badge ? strdup(badge) : NULL;
+}
+
+void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) {
+ item->eventdata = NULL;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/common/wrapper.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/wrapper.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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_WRAPPER_H
+#define UIC_WRAPPER_H
+
+#include "../ui/toolkit.h"
+#include "../ui/tree.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UIEXPORT UiContext* ui_object_get_context(UiObject *obj);
+UIEXPORT void* ui_object_get_windowdata(UiObject *obj);
+UIEXPORT void ui_object_set_windowdata(UiObject *obj, void *windowdata);
+
+UIEXPORT void* ui_list_get_data(UiList *list);
+UIEXPORT void* ui_list_get_iter(UiList *list);
+UIEXPORT void ui_list_set_iter(UiList *list, void *iter);
+
+UIEXPORT UiSubList* ui_sublist_new(void);
+UIEXPORT void ui_sublist_set_value(UiSubList *sublist, UiList *value);
+UIEXPORT void ui_sublist_set_varname(UiSubList *sublist, const char *varname);
+UIEXPORT void ui_sublist_set_header(UiSubList *sublist, const char *header);
+UIEXPORT void ui_sublist_set_separator(UiSubList *sublist, UiBool separator);
+UIEXPORT void ui_sublist_set_userdata(UiSubList *sublist, void *userdata);
+UIEXPORT void ui_sublist_free(UiSubList *sublist);
+
+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_clear(UiList *list);
+UIEXPORT int ui_srclist_size(UiList *list);
+
+UIEXPORT UiList* ui_sublist_event_get_list(UiSubListEventData *event);
+UIEXPORT int ui_sublist_event_get_sublist_index(UiSubListEventData *event);
+UIEXPORT int ui_sublist_event_get_row_index(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_row_data(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_sublist_userdata(UiSubListEventData *event);
+UIEXPORT void* ui_sublist_event_get_event_data(UiSubListEventData *event);
+
+UIEXPORT UiObject* ui_event_get_obj(UiEvent *event);
+UIEXPORT void* ui_event_get_document(UiEvent *event);
+UIEXPORT void* ui_event_get_windowdata(UiEvent *event);
+UIEXPORT void* ui_event_get_eventdata(UiEvent *event);
+UIEXPORT int ui_event_get_eventdatatype(UiEvent *event);
+UIEXPORT int ui_event_get_int(UiEvent *event);
+UIEXPORT int ui_event_get_set(UiEvent *event);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_WRAPPER_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/Makefile
--- a/ui/gtk/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -27,8 +27,10 @@
#
$(GTK_OBJPRE)%.o: gtk/%.c
- $(CC) -o $@ -c -I../ucx $(CFLAGS) $(TK_CFLAGS) $<
+ $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
$(UI_LIB): $(OBJ)
$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
-
+
+$(UI_SHLIB): $(OBJ)
+ $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/button.c
--- a/ui/gtk/button.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/button.c Sun Jul 20 22:04:39 2025 +0200
@@ -73,6 +73,7 @@
event->callback = onclick;
event->value = event_value;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
button,
@@ -96,13 +97,13 @@
return button;
}
-UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) {
+UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
UiObject* current = uic_current_obj(obj);
- GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata, 0, FALSE);
- ui_set_name_and_style(button, args.name, args.style_class);
- ui_set_widget_groups(obj->ctx, button, args.groups);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, button, FALSE);
+ GtkWidget *button = ui_create_button(obj, args->label, args->icon, 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_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, button);
return button;
}
@@ -113,6 +114,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = event->value;
e.set = ui_get_setop();
event->callback(&e, event->userdata);
@@ -137,6 +139,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = event->var->value;
+ e.eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
e.intval = i->get(i);
e.set = ui_get_setop();
@@ -149,6 +152,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = gtk_toggle_button_get_active(widget);
e.set = ui_get_setop();
event->callback(&e, event->userdata);
@@ -240,6 +244,7 @@
event->callback = onchange;
event->value = 0;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
widget,
@@ -260,6 +265,7 @@
event->callback = NULL;
event->value = enable_state;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
widget,
@@ -274,29 +280,29 @@
}
}
-static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) {
+static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs *args) {
UiObject* current = uic_current_obj(obj);
ui_setup_togglebutton(
obj,
widget,
- args.label,
- args.icon,
- args.varname,
- args.value,
- args.onchange,
- args.onchangedata,
- args.enable_group);
- ui_set_name_and_style(widget, args.name, args.style_class);
- ui_set_widget_groups(obj->ctx, widget, args.groups);
+ args->label,
+ args->icon,
+ args->varname,
+ args->value,
+ args->onchange,
+ args->onchangedata,
+ args->enable_group);
+ ui_set_name_and_style(widget, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, widget, args->groups);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, widget, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, widget);
return widget;
}
-UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) {
return togglebutton_create(obj, gtk_toggle_button_new(), args);
}
@@ -320,6 +326,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = gtk_check_button_get_active(widget);
e.set = ui_get_setop();
event->callback(&e, event->userdata);
@@ -333,39 +340,39 @@
}
}
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
UiObject* current = uic_current_obj(obj);
- GtkWidget *widget = gtk_check_button_new_with_label(args.label);
+ GtkWidget *widget = gtk_check_button_new_with_label(args->label);
ui_bind_togglebutton(
obj,
widget,
ui_check_button_get,
ui_check_button_set,
- args.varname,
- args.value,
+ args->varname,
+ args->value,
(ui_toggled_func)ui_checkbox_callback,
- args.onchange,
- args.onchangedata,
+ args->onchange,
+ args->onchangedata,
(ui_toggled_func)ui_checkbox_enable_state,
- args.enable_group);
+ args->enable_group);
- ui_set_name_and_style(widget, args.name, args.style_class);
- ui_set_widget_groups(obj->ctx, widget, args.groups);
+ ui_set_name_and_style(widget, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, widget, args->groups);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, widget, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, widget);
return widget;
}
#else
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
return togglebutton_create(obj, gtk_check_button_new(), args);
}
#endif
-UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
#ifdef UI_GTK3
return NULL; // TODO
#else
@@ -391,6 +398,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = RADIOBUTTON_GET_ACTIVE(widget);
e.set = ui_get_setop();
event->callback(&e, event->userdata);
@@ -415,13 +423,13 @@
free(data);
}
-UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
+UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
UiObject* current = uic_current_obj(obj);
GSList *rg = NULL;
UiInteger *rgroup;
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
UiBool first = FALSE;
if(var) {
@@ -432,9 +440,9 @@
}
}
- 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);
+ 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);
if(rgroup) {
#if GTK_MAJOR_VERSION >= 4
if(rg) {
@@ -476,13 +484,14 @@
rbdata);
}
- if(args.onchange) {
+ if(args->onchange) {
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = obj;
- event->userdata = args.onchangedata;
- event->callback = args.onchange;
+ event->userdata = args->onchangedata;
+ event->callback = args->onchange;
event->value = 0;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
rbutton,
@@ -496,8 +505,8 @@
event);
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, rbutton, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, rbutton);
return rbutton;
}
@@ -510,6 +519,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = i->get(i);
ui_notify_evt(i->observers, &e);
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/container.c
--- a/ui/gtk/container.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/container.c Sun Jul 20 22:04:39 2025 +0200
@@ -120,12 +120,9 @@
return (UiContainer*)ct;
}
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_box_container_add(UiContainer *ct, GtkWidget *widget) {
UiBoxContainer *bc = (UiBoxContainer*)ct;
- if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(ct->layout.fill);
- }
-
+ UiBool fill = ct->layout.fill;
if(bc->has_fill && fill) {
fprintf(stderr, "UiError: container has 2 filled widgets");
fill = FALSE;
@@ -180,7 +177,7 @@
}
#if GTK_MAJOR_VERSION >= 3
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
UiGridContainer *grid = (UiGridContainer*)ct;
if(ct->layout.newline) {
@@ -208,9 +205,7 @@
}
}
- if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(ct->layout.fill);
- }
+ UiBool fill = ct->layout.fill;
if(ct->layout.hexpand) {
hexpand = TRUE;
hfill = TRUE;
@@ -249,7 +244,7 @@
}
#endif
#ifdef UI_GTK2
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
UiGridContainer *grid = (UiGridContainer*)ct;
if(ct->layout.newline) {
@@ -277,9 +272,7 @@
}
}
- if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(ct->layout.fill);
- }
+ UiBool fill = ct->layout.fill;
if(ct->layout.hexpand) {
hexpand = TRUE;
hfill = TRUE;
@@ -340,7 +333,7 @@
return ct;
}
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget) {
FRAME_SET_CHILD(ct->widget, widget);
}
@@ -354,11 +347,11 @@
return ct;
}
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_expander_container_add(UiContainer *ct, GtkWidget *widget) {
EXPANDER_SET_CHILD(ct->widget, widget);
}
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget) {
// TODO: check if the widget implements GtkScrollable
SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
ui_reset_layout(ct->layout);
@@ -385,7 +378,7 @@
return (UiContainer*)ct;
}
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget) {
UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget);
if(!data) {
fprintf(stderr, "UI Error: widget is not a tabview");
@@ -420,15 +413,15 @@
return ret;
}
-UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) {
+UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type) {
UiObject *current = uic_current_obj(obj);
UiContainer *ct = current->container;
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
- GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
- ui_set_name_and_style(box, args.name, args.style_class);
- GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
- ct->add(ct, widget, TRUE);
+ GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
+ ui_set_name_and_style(box, args->name, args->style_class);
+ GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
+ ct->add(ct, widget);
UiObject *newobj = uic_object_new(obj, box);
newobj->container = ui_box_container(obj, box, type);
@@ -437,11 +430,11 @@
return widget;
}
-UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box_create(obj, args, UI_CONTAINER_VBOX);
}
-UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box_create(obj, args, UI_CONTAINER_HBOX);
}
@@ -458,74 +451,74 @@
return grid;
}
-UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
GtkWidget *widget;
- GtkWidget *grid = ui_create_grid_widget(args.columnspacing, args.rowspacing);
- ui_set_name_and_style(grid, args.name, args.style_class);
- widget = ui_box_set_margin(grid, args.margin);
- current->container->add(current->container, widget, TRUE);
+ GtkWidget *grid = ui_create_grid_widget(args->columnspacing, args->rowspacing);
+ ui_set_name_and_style(grid, args->name, args->style_class);
+ widget = ui_box_set_margin(grid, args->margin);
+ current->container->add(current->container, widget);
UiObject *newobj = uic_object_new(obj, grid);
- newobj->container = ui_grid_container(obj, grid, args.def_hexpand, args.def_vexpand, args.def_hfill, args.def_vfill);
+ newobj->container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
uic_obj_add(obj, newobj);
return widget;
}
-UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args) {
+UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
- GtkWidget *frame = gtk_frame_new(args.label);
+ GtkWidget *frame = gtk_frame_new(args->label);
UiObject *newobj = uic_object_new(obj, frame);
- GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+ GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
if(sub) {
FRAME_SET_CHILD(frame, sub);
} else {
newobj->widget = frame;
newobj->container = ui_frame_container(obj, frame);
}
- current->container->add(current->container, frame, FALSE);
+ current->container->add(current->container, frame);
uic_obj_add(obj, newobj);
return frame;
}
-UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args) {
+UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
- GtkWidget *expander = gtk_expander_new(args.label);
- gtk_expander_set_expanded(GTK_EXPANDER(expander), args.isexpanded);
+ GtkWidget *expander = gtk_expander_new(args->label);
+ gtk_expander_set_expanded(GTK_EXPANDER(expander), args->isexpanded);
UiObject *newobj = uic_object_new(obj, expander);
- GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+ GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
if(sub) {
EXPANDER_SET_CHILD(expander, sub);
} else {
newobj->widget = expander;
newobj->container = ui_expander_container(obj, expander);
}
- current->container->add(current->container, expander, FALSE);
+ current->container->add(current->container, expander);
uic_obj_add(obj, newobj);
return expander;
}
-UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
GtkWidget *sw = SCROLLEDWINDOW_NEW();
- ui_set_name_and_style(sw, args.name, args.style_class);
- GtkWidget *widget = ui_box_set_margin(sw, args.margin);
- current->container->add(current->container, widget, TRUE);
+ ui_set_name_and_style(sw, args->name, args->style_class);
+ GtkWidget *widget = ui_box_set_margin(sw, args->margin);
+ current->container->add(current->container, widget);
UiObject *newobj = uic_object_new(obj, sw);
- GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
+ GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
if(sub) {
SCROLLEDWINDOW_SET_CHILD(sw, sub);
} else {
@@ -689,22 +682,71 @@
return g_object_get_data(G_OBJECT(tabview), "ui_tabview");
}
+static void tabview_switch_page(
+ GtkNotebook *self,
+ GtkWidget *page,
+ guint page_num,
+ gpointer userdata)
+{
+ UiGtkTabView *tabview = userdata;
+ if(!tabview->onchange) {
+ return;
+ }
+
+ UiEvent event;
+ event.obj = tabview->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.set = ui_get_setop();
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = page_num;
+
+ tabview->onchange(&event, tabview->onchange);
+}
+
+#if GTK_CHECK_VERSION(3, 10, 0)
+
+static void tabview_stack_changed(
+ GObject *object,
+ GParamSpec *pspec,
+ UiGtkTabView *tabview)
+{
+ if(!tabview->onchange) {
+ return;
+ }
+
+ UiEvent event;
+ event.obj = tabview->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.set = ui_get_setop();
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = 0;
+
+ tabview->onchange(&event, tabview->onchange);
+}
+
+#endif
+
typedef int64_t(*ui_tabview_get_func)(UiInteger*);
typedef void (*ui_tabview_set_func)(UiInteger*, int64_t);
-UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
+UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
UiGtkTabView *data = malloc(sizeof(UiGtkTabView));
- data->margin = args.margin;
- data->spacing = args.spacing;
- data->columnspacing = args.columnspacing;
- data->rowspacing = args.rowspacing;
+ memset(data, 0, sizeof(UiGtkTabView));
+ data->margin = args->margin;
+ data->spacing = args->spacing;
+ data->columnspacing = args->columnspacing;
+ data->rowspacing = args->rowspacing;
ui_tabview_get_func getfunc = NULL;
ui_tabview_set_func setfunc = NULL;
GtkWidget *widget = NULL;
GtkWidget *data_widget = NULL;
- switch(args.tabview) {
+ switch(args->tabview) {
case UI_TABVIEW_DOC: {
// TODO
break;
@@ -715,6 +757,7 @@
GtkWidget *sidebar = gtk_stack_sidebar_new();
BOX_ADD(widget, sidebar);
GtkWidget *stack = gtk_stack_new();
+ g_signal_connect(stack, "notify::visible-child", G_CALLBACK(tabview_stack_changed), data);
gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN);
gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack));
BOX_ADD_EXPAND(widget, stack);
@@ -734,13 +777,18 @@
case UI_TABVIEW_INVISIBLE: /* fall through */
case UI_TABVIEW_NAVIGATION_TOP2: {
widget = gtk_notebook_new();
+ g_signal_connect(
+ widget,
+ "switch-page",
+ G_CALLBACK(tabview_switch_page),
+ data);
data_widget = widget;
data->select_tab = ui_notebook_tab_select;
data->remove_tab = ui_notebook_tab_remove;
data->add_tab = ui_notebook_tab_add;
getfunc = ui_notebook_get;
setfunc = ui_notebook_set;
- if(args.tabview == UI_TABVIEW_INVISIBLE) {
+ if(args->tabview == UI_TABVIEW_INVISIBLE) {
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE);
gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE);
}
@@ -749,8 +797,8 @@
}
UiObject* current = uic_current_obj(obj);
- if(args.value || args.varname) {
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ if(args->value || args->varname) {
+ UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
UiInteger *i = var->value;
i->get = getfunc;
i->set = setfunc;
@@ -759,10 +807,10 @@
g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
data->widget = data_widget;
- data->subcontainer = args.subcontainer;
+ data->subcontainer = args->subcontainer;
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, widget, TRUE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, widget);
UiObject *newobj = uic_object_new(obj, widget);
newobj->container = ui_tabview_container(obj, widget);
@@ -872,14 +920,14 @@
hb_set_part(obj, 1);
}
-UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) {
UiObject *current = uic_current_obj(obj);
UiContainer *ct = current->container;
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
- GtkWidget *box = ui_gtk_hbox_new(args.alt_spacing);
- ui_set_name_and_style(box, args.name, args.style_class);
- ct->add(ct, box, FALSE);
+ GtkWidget *box = ui_gtk_hbox_new(args->alt_spacing);
+ ui_set_name_and_style(box, args->name, args->style_class);
+ ct->add(ct, box);
UiObject *newobj = uic_object_new(obj, box);
newobj->container = ui_headerbar_fallback_container(obj, box);
@@ -910,14 +958,14 @@
return (UiContainer*)ct;
}
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget) {
UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
BOX_ADD(ct->widget, widget);
}
#if GTK_CHECK_VERSION(3, 10, 0)
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar");
if(!headerbar) {
return ui_headerbar_fallback_create(obj, args);
@@ -940,7 +988,7 @@
return (UiContainer*)ct;
}
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget) {
UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
if(hb->part == 0) {
UI_HEADERBAR_PACK_START(ct->widget, widget);
@@ -958,7 +1006,7 @@
#else
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
return ui_headerbar_fallback_create(obj, args);
}
@@ -967,15 +1015,15 @@
/* -------------------- Sidebar -------------------- */
#ifdef UI_LIBADWAITA
-UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
+UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
if(!sidebar_toolbar_view) {
fprintf(stderr, "Error: window is not configured for sidebar\n");
return NULL;
}
- GtkWidget *box = ui_gtk_vbox_new(args.spacing);
- ui_box_set_margin(box, args.margin);
+ GtkWidget *box = ui_gtk_vbox_new(args->spacing);
+ ui_box_set_margin(box, args->margin);
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
UiObject *newobj = uic_object_new(obj, box);
@@ -985,11 +1033,11 @@
return box;
}
#else
-UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
+UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
- GtkWidget *box = ui_gtk_vbox_new(args.spacing);
- ui_box_set_margin(box, args.margin);
+ GtkWidget *box = ui_gtk_vbox_new(args->spacing);
+ ui_box_set_margin(box, args->margin);
BOX_ADD_EXPAND(sidebar_vbox, box);
UiObject *newobj = uic_object_new(obj, box);
@@ -1019,18 +1067,18 @@
-static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs args) {
+static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs *args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *pane0 = create_paned(orientation);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, pane0, TRUE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, pane0);
- int max = args.max_panes == 0 ? 2 : args.max_panes;
+ int max = args->max_panes == 0 ? 2 : args->max_panes;
UiObject *newobj = uic_object_new(obj, pane0);
- newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args.initial_position);
+ newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position);
uic_obj_add(obj, newobj);
g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container);
@@ -1038,11 +1086,11 @@
return pane0;
}
-UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args) {
+UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
return splitpane_create(obj, UI_HORIZONTAL, args);
}
-UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args) {
+UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
return splitpane_create(obj, UI_VERTICAL, args);
}
@@ -1058,7 +1106,7 @@
return (UiContainer*)ct;
}
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) {
UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct;
if(s->nchildren >= s->max) {
@@ -1151,7 +1199,7 @@
UiObject *item_obj = cxMapGet(ct->current_items, key);
if(item_obj) {
// re-add previously created widget
- ui_box_container_add(ct->container, item_obj->widget, FALSE);
+ ui_box_container_add(ct->container, item_obj->widget);
} else {
// create new widget and object for this list element
CxMempool *mp = cxMempoolCreateSimple(256);
@@ -1166,7 +1214,7 @@
ct->columnspacing,
ct->rowspacing,
ct->margin);
- ui_box_container_add(ct->container, obj->widget, FALSE);
+ ui_box_container_add(ct->container, obj->widget);
if(ct->create_ui) {
ct->create_ui(obj, index, elm, ct->userdata);
}
@@ -1175,6 +1223,10 @@
elm = list->next(list);
index++;
}
+
+#if GTK_MAJOR_VERSION < 4
+ gtk_widget_show_all(ct->widget);
+#endif
}
static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) {
@@ -1183,33 +1235,33 @@
free(container);
}
-UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) {
+UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
UiObject *current = uic_current_obj(obj);
UiContainer *ct = current->container;
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
- GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
- ui_set_name_and_style(box, args.name, args.style_class);
- GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
- ct->add(ct, widget, TRUE);
+ GtkWidget *box = args->container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
+ ui_set_name_and_style(box, args->name, args->style_class);
+ GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
+ ct->add(ct, widget);
UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
container->parent = obj;
container->widget = box;
- container->container = ui_box_container(current, box, args.container);
- container->create_ui = args.create_ui;
- container->userdata = args.userdata;
- container->subcontainer = args.subcontainer;
+ container->container = ui_box_container(current, box, args->container);
+ container->create_ui = args->create_ui;
+ container->userdata = args->userdata;
+ container->subcontainer = args->subcontainer;
container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
container->current_items->collection.advanced_destructor = remove_item;
container->current_items->collection.destructor_data = container;
- container->margin = args.sub_margin;
- container->spacing = args.sub_spacing;
- container->columnspacing = args.sub_columnspacing;
- container->rowspacing = args.sub_rowspacing;
+ container->margin = args->sub_margin;
+ container->spacing = args->sub_spacing;
+ container->columnspacing = args->sub_columnspacing;
+ container->rowspacing = args->sub_rowspacing;
container->remove_items = TRUE;
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_LIST);
if(var) {
UiList *list = var->value;
list->obj = container;
@@ -1236,7 +1288,7 @@
void ui_layout_fill(UiObject *obj, UiBool fill) {
UiContainer *ct = uic_get_current_container(obj);
- ct->layout.fill = ui_bool2lb(fill);
+ ct->layout.fill = fill;
}
void ui_layout_hexpand(UiObject *obj, UiBool expand) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/container.h
--- a/ui/gtk/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -44,23 +44,15 @@
#endif
#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
-#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE)
-#define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE)
-typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*, UiBool);
+typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*);
typedef struct UiDocumentView UiDocumentView;
-typedef enum UiLayoutBool {
- UI_LAYOUT_UNDEFINED = 0,
- UI_LAYOUT_TRUE,
- UI_LAYOUT_FALSE,
-} UiLayoutBool;
-
typedef struct UiLayout UiLayout;
struct UiLayout {
- UiLayoutBool fill;
+ UiBool fill;
UiBool newline;
char *label;
UiBool hexpand;
@@ -78,7 +70,7 @@
UIMENU menu;
GtkWidget *current;
- void (*add)(UiContainer*, GtkWidget*, UiBool);
+ void (*add)(UiContainer*, GtkWidget*);
UiLayout layout;
int close;
@@ -122,6 +114,8 @@
int spacing;
int columnspacing;
int rowspacing;
+ ui_callback onchange;
+ void *onchangedata;
} UiGtkTabView;
@@ -170,13 +164,13 @@
int margin);
UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
GtkWidget* ui_box_set_margin(GtkWidget *box, int margin);
-UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type);
+UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type);
UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_box_container_add(UiContainer *ct, GtkWidget *widget);
GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing);
UiContainer* ui_grid_container(
@@ -186,22 +180,22 @@
UiBool def_vexpand,
UiBool def_hfill,
UiBool def_vfill);
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_grid_container_add(UiContainer *ct, GtkWidget *widget);
UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander);
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_expander_container_add(UiContainer *ct, GtkWidget *widget);
UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget);
UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget);
UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget);
UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview);
@@ -210,11 +204,11 @@
#if GTK_CHECK_VERSION(3, 10, 0)
UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget);
#endif
UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
+void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget);
#ifdef __cplusplus
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/display.c
--- a/ui/gtk/display.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/display.c Sun Jul 20 22:04:39 2025 +0200
@@ -46,19 +46,19 @@
#endif
}
-UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs args) {
+UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
UiObject* current = uic_current_obj(obj);
const char *css_class = NULL;
char *markup = NULL;
- if(args.label) {
+ if(args->label) {
#if GTK_MAJOR_VERSION < 3
- switch(args.style) {
+ switch(args->style) {
case UI_LABEL_STYLE_DEFAULT: break;
case UI_LABEL_STYLE_TITLE: {
- cxmutstr m = cx_asprintf("%s", args.label);
+ cxmutstr m = cx_asprintf("%s", args->label);
markup = m.ptr;
- args.label = NULL;
+ args->label = NULL;
}
case UI_LABEL_STYLE_SUBTITLE: {
break;
@@ -68,7 +68,7 @@
}
}
# else
- switch(args.style) {
+ switch(args->style) {
case UI_LABEL_STYLE_DEFAULT: break;
case UI_LABEL_STYLE_TITLE: {
css_class = "ui_label_title";
@@ -87,7 +87,7 @@
}
- GtkWidget *widget = gtk_label_new(args.label);
+ GtkWidget *widget = gtk_label_new(args->label);
if(markup) {
gtk_label_set_markup(GTK_LABEL(widget), markup);
free(markup);
@@ -97,7 +97,7 @@
WIDGET_ADD_CSS_CLASS(widget, css_class);
}
- switch(args.align) {
+ switch(args->align) {
case UI_ALIGN_DEFAULT: break;
case UI_ALIGN_LEFT: set_alignment(widget, 0, .5); break;
case UI_ALIGN_RIGHT: set_alignment(widget, 1, .5); break;
@@ -105,7 +105,7 @@
}
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
UiString* value = (UiString*)var->value;
value->obj = widget;
@@ -113,19 +113,19 @@
value->set = ui_label_set;
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, widget, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, widget);
return widget;
}
-UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) {
- args.align = UI_ALIGN_LEFT;
+UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_LEFT;
return ui_label_create(obj, args);
}
-UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args) {
- args.align = UI_ALIGN_RIGHT;
+UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_RIGHT;
return ui_label_create(obj, args);
}
@@ -150,7 +150,7 @@
UIWIDGET ui_space_deprecated(UiObject *obj) {
GtkWidget *widget = gtk_label_new("");
UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget, TRUE);
+ ct->add(ct, widget);
return widget;
}
@@ -162,7 +162,7 @@
GtkWidget *widget = gtk_hseparator_new();
#endif
UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget, FALSE);
+ ct->add(ct, widget);
return widget;
}
@@ -174,14 +174,14 @@
double max;
} UiProgressBarRange;
-UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) {
+UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *progressbar = gtk_progress_bar_new();
- if(args.max > args.min) {
+ if(args->max > args->min) {
UiProgressBarRange *range = malloc(sizeof(UiProgressBarRange));
- range->min = args.min;
- range->max = args.max;
+ range->min = args->min;
+ range->max = args->max;
g_signal_connect(
progressbar,
"destroy",
@@ -191,7 +191,7 @@
}
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_DOUBLE);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_DOUBLE);
if(var && var->value) {
UiDouble *value = var->value;
value->get = ui_progressbar_get;
@@ -200,8 +200,8 @@
ui_progressbar_set(value, value->value);
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, progressbar, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, progressbar);
return progressbar;
}
@@ -228,12 +228,12 @@
/* ------------------------- progress spinner ------------------------- */
-UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args) {
+UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *spinner = gtk_spinner_new();
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var && var->value) {
UiInteger *value = var->value;
value->get = ui_spinner_get;
@@ -242,8 +242,8 @@
ui_spinner_set(value, value->value);
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, spinner, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, spinner);
return spinner;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/entry.c
--- a/ui/gtk/entry.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/entry.c Sun Jul 20 22:04:39 2025 +0200
@@ -35,24 +35,24 @@
#include "entry.h"
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args) {
+UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
double min = 0;
double max = 1000;
UiObject* current = uic_current_obj(obj);
UiVar *var = NULL;
- if(args.varname) {
- var = uic_get_var(obj->ctx, args.varname);
+ if(args->varname) {
+ var = uic_get_var(obj->ctx, args->varname);
}
if(!var) {
- if(args.intvalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args.intvalue, NULL, UI_VAR_INTEGER);
- } else if(args.doublevalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args.doublevalue, NULL, UI_VAR_DOUBLE);
- } else if(args.rangevalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args.rangevalue, NULL, UI_VAR_RANGE);
+ if(args->intvalue) {
+ var = uic_widget_var(obj->ctx, current->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
+ } else if(args->doublevalue) {
+ var = uic_widget_var(obj->ctx, current->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
+ } else if(args->rangevalue) {
+ var = uic_widget_var(obj->ctx, current->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
}
}
@@ -61,18 +61,18 @@
min = r->min;
max = r->max;
}
- if(args.step == 0) {
- args.step = 1;
+ if(args->step == 0) {
+ args->step = 1;
}
#ifdef UI_GTK2LEGACY
if(min == max) {
max = min + 1;
}
#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);
- gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args.digits);
+ 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);
+ gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args->digits);
UiObserver **obs = NULL;
if(var) {
double value = 0;
@@ -115,8 +115,8 @@
event->obj = obj;
event->var = var;
event->observers = obs;
- event->callback = args.onchange;
- event->userdata = args.onchangedata;
+ event->callback = args->onchange;
+ event->userdata = args->onchangedata;
g_signal_connect(
spin,
@@ -129,8 +129,8 @@
G_CALLBACK(ui_destroy_vardata),
event);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, spin, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, spin);
return spin;
}
@@ -150,7 +150,8 @@
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
- e.eventdata = &value;
+ e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = (int64_t)value;
if(event->callback) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/graphics.c
--- a/ui/gtk/graphics.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/graphics.c Sun Jul 20 22:04:39 2025 +0200
@@ -45,7 +45,7 @@
}
UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget, TRUE);
+ ct->add(ct, widget);
return widget;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/image.c
--- a/ui/gtk/image.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/image.c Sun Jul 20 22:04:39 2025 +0200
@@ -63,7 +63,7 @@
#endif
-UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
+UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
UiObject *current = uic_current_obj(obj);
GtkWidget *drawingarea = gtk_drawing_area_new();
@@ -78,10 +78,10 @@
widget = eventbox;
#endif
- if(args.scrollarea) {
+ if(args->scrollarea) {
toplevel = SCROLLEDWINDOW_NEW();
SCROLLEDWINDOW_SET_CHILD(toplevel, widget);
- args.adjustwidgetsize = TRUE;
+ args->adjustwidgetsize = TRUE;
} else {
toplevel = widget;
}
@@ -89,29 +89,29 @@
UiImageViewer *imgviewer = malloc(sizeof(UiImageViewer));
memset(imgviewer, 0, sizeof(UiImageViewer));
imgviewer->obj = obj;
- imgviewer->onbuttonpress = args.onbuttonpress;
- imgviewer->onbuttonpressdata = args.onbuttonpressdata;
- imgviewer->onbuttonrelease = args.onbuttonrelease;
- imgviewer->onbuttonreleasedata = args.onbuttonreleasedata;
- if(args.image_padding > 0) {
- imgviewer->padding_left = args.image_padding;
- imgviewer->padding_right = args.image_padding;
- imgviewer->padding_top = args.image_padding;
- imgviewer->padding_bottom = args.image_padding;
+ imgviewer->onbuttonpress = args->onbuttonpress;
+ imgviewer->onbuttonpressdata = args->onbuttonpressdata;
+ imgviewer->onbuttonrelease = args->onbuttonrelease;
+ imgviewer->onbuttonreleasedata = args->onbuttonreleasedata;
+ if(args->image_padding > 0) {
+ imgviewer->padding_left = args->image_padding;
+ imgviewer->padding_right = args->image_padding;
+ imgviewer->padding_top = args->image_padding;
+ imgviewer->padding_bottom = args->image_padding;
} else {
- imgviewer->padding_left = args.image_padding_left;
- imgviewer->padding_right = args.image_padding_right;
- imgviewer->padding_top = args.image_padding_top;
- imgviewer->padding_bottom = args.image_padding_bottom;
+ imgviewer->padding_left = args->image_padding_left;
+ imgviewer->padding_right = args->image_padding_right;
+ imgviewer->padding_top = args->image_padding_top;
+ imgviewer->padding_bottom = args->image_padding_bottom;
}
- imgviewer->adjustwidgetsize = args.adjustwidgetsize;
- imgviewer->autoscale = args.autoscale;
- imgviewer->useradjustable = args.useradjustable;
+ imgviewer->adjustwidgetsize = args->adjustwidgetsize;
+ imgviewer->autoscale = args->autoscale;
+ imgviewer->useradjustable = args->useradjustable;
imgviewer->zoom_scale = 20;
g_object_set_data_full(G_OBJECT(drawingarea), "uiimageviewer", imgviewer, (GDestroyNotify)imageviewer_destroy);
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC);
+ UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
imgviewer->var = var;
imgviewer->widget = drawingarea;
@@ -136,7 +136,7 @@
imgviewer,
NULL);
- if(args.useradjustable) {
+ if(args->useradjustable) {
gtk_widget_set_focusable(drawingarea, TRUE);
}
@@ -182,13 +182,13 @@
#endif
- if(args.contextmenu) {
- UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, widget);
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, widget);
ui_widget_set_contextmenu(widget, menu);
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, toplevel, TRUE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, toplevel);
return toplevel;
}
@@ -336,6 +336,28 @@
g_object_unref(pixbuf);
} else {
obj->value = pixbuf;
+ obj->type = UI_IMAGE_OBJECT_TYPE;
+ }
+
+ return 0;
+}
+
+UIEXPORT int ui_image_load_data(UiGeneric *obj, const void *imgdata, size_t size) {
+ GBytes *bytes = g_bytes_new_static(imgdata, size);
+ GInputStream *in = g_memory_input_stream_new_from_bytes(bytes);
+ GError *error = NULL;
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(in, NULL, &error);
+ g_object_unref(in);
+ if(!pixbuf) {
+ return 1;
+ }
+
+ if(obj->set) {
+ obj->set(obj, pixbuf, UI_IMAGE_OBJECT_TYPE);
+ g_object_unref(pixbuf);
+ } else {
+ obj->value = pixbuf;
+ obj->type = UI_IMAGE_OBJECT_TYPE;
}
return 0;
@@ -416,6 +438,7 @@
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata = NULL;
+ event.eventdatatype = 0;
event.intval = gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(gesture));
event.set = 0;
callback(&event, userdata);
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/list.c
--- a/ui/gtk/list.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/list.c Sun Jul 20 22:04:39 2025 +0200
@@ -48,6 +48,15 @@
return column == 0 ? elm : NULL;
}
+static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
+ if(model->getvalue2) {
+ return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
+ } else if(model->getvalue) {
+ return model->getvalue(elm, col);
+ }
+ return NULL;
+}
+
/*
static GtkTargetEntry targetentries[] =
{
@@ -73,6 +82,7 @@
typedef struct _ObjWrapper {
GObject parent_instance;
void *data;
+ int i;
} ObjWrapper;
typedef struct _ObjWrapperClass {
@@ -89,9 +99,10 @@
self->data = NULL;
}
-ObjWrapper* obj_wrapper_new(void* data) {
+ObjWrapper* obj_wrapper_new(void* data, int i) {
ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL);
obj->data = data;
+ obj->i = i;
return obj;
}
@@ -122,20 +133,21 @@
static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
UiColData *col = userdata;
+ UiList *list = col->listview->var ? col->listview->var->value : NULL;
ObjWrapper *obj = gtk_list_item_get_item(item);
UiModel *model = col->listview->model;
UiModelType type = model->types[col->model_column];
- void *data = model->getvalue(obj->data, col->data_column);
+ UiBool freevalue = FALSE;
+ void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
GtkWidget *child = gtk_list_item_get_child(item);
- bool freevalue = TRUE;
switch(type) {
+ case UI_STRING_FREE: {
+ freevalue = TRUE;
+ }
case UI_STRING: {
- freevalue = FALSE;
- }
- case UI_STRING_FREE: {
gtk_label_set_label(GTK_LABEL(child), data);
if(freevalue) {
free(data);
@@ -157,10 +169,13 @@
break;
}
case UI_ICON_TEXT: {
- freevalue = FALSE;
+
}
case UI_ICON_TEXT_FREE: {
- void *data2 = model->getvalue(obj->data, col->data_column+1);
+ void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
+ if(type == UI_ICON_TEXT_FREE) {
+ freevalue = TRUE;
+ }
GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
if(data && image) {
@@ -189,34 +204,41 @@
return selection_model;
}
-static UiListView* create_listview(UiObject *obj, UiListArgs args) {
+static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
UiListView *tableview = malloc(sizeof(UiListView));
memset(tableview, 0, sizeof(UiListView));
tableview->obj = obj;
- tableview->model = args.model;
- tableview->onactivate = args.onactivate;
- tableview->onactivatedata = args.onactivatedata;
- tableview->onselection = args.onselection;
- tableview->onselectiondata = args.onselectiondata;
- tableview->ondragstart = args.ondragstart;
- tableview->ondragstartdata = args.ondragstartdata;
- tableview->ondragcomplete = args.ondragcomplete;
- tableview->ondragcompletedata = args.ondragcompletedata;
- tableview->ondrop = args.ondrop;
- tableview->ondropdata = args.ondropsdata;
+ tableview->model = args->model;
+ tableview->onactivate = args->onactivate;
+ tableview->onactivatedata = args->onactivatedata;
+ tableview->onselection = args->onselection;
+ tableview->onselectiondata = args->onselectiondata;
+ tableview->ondragstart = args->ondragstart;
+ tableview->ondragstartdata = args->ondragstartdata;
+ tableview->ondragcomplete = args->ondragcomplete;
+ tableview->ondragcompletedata = args->ondragcompletedata;
+ tableview->ondrop = args->ondrop;
+ tableview->ondropdata = args->ondropdata;
tableview->selection.count = 0;
tableview->selection.rows = NULL;
return tableview;
}
-UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
// to simplify things and share code with ui_table_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
- args.model = model;
+ if(args->getvalue2) {
+ model->getvalue2 = args->getvalue2;
+ model->getvalue2data = args->getvalue2data;
+ } else if(args->getvalue) {
+ model->getvalue = args->getvalue;
+ } else {
+ model->getvalue = ui_strmodel_getvalue;
+ }
+ args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
@@ -230,10 +252,10 @@
g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
- GtkSelectionModel *selection_model = create_selection_model(listview, ls, args.multiselection);
+ GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
// init listview
listview->widget = view;
@@ -256,19 +278,23 @@
list->setselection = ui_listview_setselection2;
ui_update_liststore(ls, list);
- } else if (args.static_elements && args.static_nelm > 0) {
- listview_copy_static_elements(listview, args.static_elements, args.static_nelm);
+ } else if (args->static_elements && args->static_nelm > 0) {
+ listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
// event handling
- if(args.onactivate) {
+ if(args->onactivate) {
// columnview and listview can use the same callback function, because
// the first parameter (which is technically a different pointer type)
// is ignored
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
}
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
@@ -278,8 +304,8 @@
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, scroll_area, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, scroll_area);
// ct->current should point to view, not scroll_area, to make it possible
// to add a context menu
@@ -288,14 +314,21 @@
return scroll_area;
}
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
// 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);
- model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
- args.model = model;
+ if(args->getvalue2) {
+ model->getvalue2 = args->getvalue2;
+ model->getvalue2data = args->getvalue2data;
+ } else if(args->getvalue) {
+ model->getvalue = args->getvalue;
+ } else {
+ model->getvalue = ui_strmodel_getvalue;
+ }
+ args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
@@ -312,7 +345,7 @@
GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
// init listview
listview->widget = view;
@@ -335,20 +368,20 @@
list->setselection = ui_combobox_setselection;
ui_update_liststore(ls, list);
- } else if (args.static_elements && args.static_nelm > 0) {
- listview_copy_static_elements(listview, args.static_elements, args.static_nelm);
+ } else if (args->static_elements && args->static_nelm > 0) {
+ listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
// event handling
- if(args.onactivate) {
+ if(args->onactivate) {
g_signal_connect(view, "notify::selected", G_CALLBACK(ui_dropdown_notify), listview);
}
// add widget to parent
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, view, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, view);
return view;
}
@@ -361,7 +394,7 @@
gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
}
-UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
@@ -371,10 +404,10 @@
// and list updates
UiListView *tableview = create_listview(obj, args);
- GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args.multiselection);
+ GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
// init tableview
tableview->widget = view;
@@ -389,7 +422,7 @@
// create columns from UiModel
- UiModel *model = args.model;
+ UiModel *model = args->model;
int columns = model ? model->columns : 0;
tableview->columns = calloc(columns, sizeof(UiColData));
@@ -435,9 +468,13 @@
}
// event handling
- if(args.onactivate) {
+ if(args->onactivate) {
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
}
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
@@ -447,8 +484,8 @@
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, scroll_area, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, scroll_area);
// ct->current should point to view, not scroll_area, to make it possible
// to add a context menu
@@ -474,6 +511,7 @@
event.window = event.obj->window;
event.intval = view->selection.count;
event.eventdata = &view->selection;
+ event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
event.set = ui_get_setop();
if(cb) {
cb(&event, cbdata);
@@ -517,6 +555,7 @@
event.window = event.obj->window;
event.intval = index;
event.eventdata = eventdata->data;
+ event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
event.set = ui_get_setop();
view->onactivate(&event, view->onactivatedata);
}
@@ -554,6 +593,7 @@
event.window = event.obj->window;
event.intval = view->selection.count;
event.eventdata = &view->selection;
+ event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
event.set = ui_get_setop();
view->onactivate(&event, view->onactivatedata);
}
@@ -561,9 +601,10 @@
void ui_update_liststore(GListStore *liststore, UiList *list) {
g_list_store_remove_all(liststore);
+ int i = 0;
void *elm = list->first(list);
while(elm) {
- ObjWrapper *obj = obj_wrapper_new(elm);
+ ObjWrapper *obj = obj_wrapper_new(elm, i++);
g_list_store_append(liststore, obj);
elm = list->next(list);
}
@@ -572,7 +613,7 @@
void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) {
g_list_store_remove_all(liststore);
for(int i=0;iget(list, i);
if(value) {
- ObjWrapper *obj = obj_wrapper_new(value);
+ ObjWrapper *obj = obj_wrapper_new(value, i);
// TODO: if index i is selected, the selection is lost
// is it possible to update the item without removing it?
- g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
+ int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
+ if(count <= i) {
+ g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1);
+ } else {
+ g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
+ }
}
}
}
@@ -649,19 +695,22 @@
#else
-static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) {
+static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
// set column values
int c = 0;
for(int i=0;icolumns;i++,c++) {
- void *data = model->getvalue(elm, c);
+ UiBool freevalue = FALSE;
+ void *data = model_getvalue(model, list, elm, row, c, &freevalue);
GValue value = G_VALUE_INIT;
switch(model->types[i]) {
- case UI_STRING:
case UI_STRING_FREE: {
+ freevalue = TRUE;
+ }
+ case UI_STRING: {
g_value_init(&value, G_TYPE_STRING);
g_value_set_string(&value, data);
- if(model->types[i] == UI_STRING_FREE) {
+ if(freevalue) {
free(data);
}
break;
@@ -714,11 +763,12 @@
}
#endif
c++;
-
- char *str = model->getvalue(elm, c);
+
+ freevalue = FALSE;
+ char *str = model_getvalue(model, list, elm, row, c, &freevalue);
g_value_init(&value, G_TYPE_STRING);
g_value_set_string(&value, str);
- if(model->types[i] == UI_ICON_TEXT_FREE) {
+ if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
free(str);
}
break;
@@ -751,12 +801,13 @@
if(list) {
void *elm = list->first(list);
+ int i = 0;
while(elm) {
// insert new row
GtkTreeIter iter;
gtk_list_store_insert (store, &iter, -1);
- update_list_row(store, &iter, model, elm);
+ update_list_row(store, &iter, model, list, elm, i++);
// next row
elm = list->next(list);
@@ -767,13 +818,13 @@
}
-UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
// 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_name_and_style(view, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, view, args->groups);
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);
@@ -790,9 +841,16 @@
#endif
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+ if(args->getvalue2) {
+ model->getvalue2 = args->getvalue2;
+ model->getvalue2data = args->getvalue2data;
+ } else if(args->getvalue) {
+ model->getvalue = args->getvalue;
+ } else {
+ model->getvalue = ui_strmodel_getvalue;
+ }
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
UiList *list = var ? var->value : NULL;
GtkListStore *listmodel = create_list_store(list, model);
@@ -822,24 +880,24 @@
// add callback
UiTreeEventData *event = malloc(sizeof(UiTreeEventData));
event->obj = obj;
- event->activate = args.onactivate;
- event->activatedata = args.onactivatedata;
- event->selection = args.onselection;
- event->selectiondata = args.onselectiondata;
+ event->activate = args->onactivate;
+ event->activatedata = args->onactivatedata;
+ event->selection = args->onselection;
+ event->selectiondata = args->onselectiondata;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
- if(args.onactivate) {
+ if(args->onactivate) {
g_signal_connect(
view,
"row-activated",
G_CALLBACK(ui_listview_activate_event),
event);
}
- if(args.onselection) {
+ if(args->onselection) {
GtkTreeSelection *selection = gtk_tree_view_get_selection(
GTK_TREE_VIEW(view));
g_signal_connect(
@@ -848,8 +906,8 @@
G_CALLBACK(ui_listview_selection_event),
event);
}
- if(args.contextmenu) {
- UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
ui_widget_set_contextmenu(view, menu);
}
@@ -862,7 +920,7 @@
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->add(current->container, scroll_area, FALSE);
// ct->current should point to view, not scroll_area, to make it possible
@@ -883,13 +941,13 @@
gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
}
-UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
// create treeview
GtkWidget *view = gtk_tree_view_new();
- UiModel *model = args.model;
+ UiModel *model = args->model;
int columns = model ? model->columns : 0;
int addi = 0;
@@ -946,7 +1004,7 @@
#endif
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
UiList *list = var ? var->value : NULL;
GtkListStore *listmodel = create_list_store(list, model);
@@ -964,12 +1022,12 @@
tableview->widget = view;
tableview->var = var;
tableview->model = model;
- tableview->ondragstart = args.ondragstart;
- tableview->ondragstartdata = args.ondragstartdata;
- tableview->ondragcomplete = args.ondragcomplete;
- tableview->ondragcompletedata = args.ondragcompletedata;
- tableview->ondrop = args.ondrop;
- tableview->ondropdata = args.ondropsdata;
+ tableview->ondragstart = args->ondragstart;
+ tableview->ondragstartdata = args->ondragstartdata;
+ tableview->ondragcomplete = args->ondragcomplete;
+ tableview->ondragcompletedata = args->ondragcompletedata;
+ tableview->ondrop = args->ondrop;
+ tableview->ondropdata = args->ondropdata;
tableview->selection.count = 0;
tableview->selection.rows = NULL;
g_signal_connect(
@@ -987,18 +1045,18 @@
// add callback
UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
event->obj = obj;
- event->activate = args.onactivate;
- event->selection = args.onselection;
- event->activatedata = args.onactivatedata;
- event->selectiondata = args.onselectiondata;
- if(args.onactivate) {
+ event->activate = args->onactivate;
+ event->selection = args->onselection;
+ event->activatedata = args->onactivatedata;
+ event->selectiondata = args->onselectiondata;
+ if(args->onactivate) {
g_signal_connect(
view,
"row-activated",
G_CALLBACK(ui_listview_activate_event),
event);
}
- if(args.onselection) {
+ if(args->onselection) {
GtkTreeSelection *selection = gtk_tree_view_get_selection(
GTK_TREE_VIEW(view));
g_signal_connect(
@@ -1010,15 +1068,15 @@
// TODO: destroy callback
- if(args.ondragstart) {
- ui_listview_add_dnd(tableview, &args);
+ if(args->ondragstart) {
+ ui_listview_add_dnd(tableview, args);
}
- if(args.ondrop) {
- ui_listview_enable_drop(tableview, &args);
+ if(args->ondrop) {
+ ui_listview_enable_drop(tableview, args);
}
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
- if(args.multiselection) {
+ if(args->multiselection) {
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
}
@@ -1030,8 +1088,8 @@
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- if(args.contextmenu) {
- UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, scroll_area);
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, scroll_area);
#if GTK_MAJOR_VERSION >= 4
ui_widget_set_contextmenu(scroll_area, menu);
#else
@@ -1039,7 +1097,7 @@
#endif
}
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->add(current->container, scroll_area, FALSE);
// ct->current should point to view, not scroll_area, to make it possible
@@ -1062,7 +1120,7 @@
GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
GtkTreeIter iter;
if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
- update_list_row(GTK_LIST_STORE(store), &iter, view->model, elm);
+ update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
}
}
}
@@ -1089,18 +1147,25 @@
/* --------------------------- ComboBox --------------------------- */
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
-
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+ if(args->getvalue2) {
+ model->getvalue2 = args->getvalue2;
+ model->getvalue2data = args->getvalue2data;
+ } else if(args->getvalue) {
+ model->getvalue = args->getvalue;
+ } else {
+ model->getvalue = ui_strmodel_getvalue;
+ }
- GtkWidget *combobox = ui_create_combobox(obj, model, var, args.static_elements, args.static_nelm, args.onactivate, args.onactivatedata);
- ui_set_name_and_style(combobox, args.name, args.style_class);
- ui_set_widget_groups(obj->ctx, combobox, args.groups);
- UI_APPLY_LAYOUT1(current, args);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+
+ GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
+ ui_set_name_and_style(combobox, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, combobox, args->groups);
+ UI_APPLY_LAYOUT2(current, args);
current->container->add(current->container, combobox, FALSE);
current->container->current = combobox;
return combobox;
@@ -1323,6 +1388,7 @@
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata = dnd;
+ event.eventdatatype = UI_EVENT_DATA_DND;
event.intval = 0;
event.set = ui_get_setop();
listview->ondragstart(&event, listview->ondragstartdata);
@@ -1359,6 +1425,7 @@
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
+ event.eventdatatype = UI_EVENT_DATA_DND;
event.intval = 0;
event.set = ui_get_setop();
listview->ondragcomplete(&event, listview->ondragcompletedata);
@@ -1388,6 +1455,7 @@
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
+ event.eventdatatype = UI_EVENT_DATA_DND;
event.intval = 0;
event.set = ui_get_setop();
listview->ondrop(&event, listview->ondropdata);
@@ -1745,7 +1813,7 @@
cxListAdd(sublists, &uisublist);
}
-UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
+UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
UiObject* current = uic_current_obj(obj);
#ifdef UI_GTK3
@@ -1753,7 +1821,7 @@
#else
GtkWidget *listbox = gtk_list_box_new();
#endif
- if(!args.style_class) {
+ if(!args->style_class) {
#if GTK_MAJOR_VERSION >= 4
WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar");
#else
@@ -1764,31 +1832,32 @@
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
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_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, scroll_area, TRUE);
+ ui_set_name_and_style(listbox, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, listbox, args->groups);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, scroll_area);
UiListBox *uilistbox = malloc(sizeof(UiListBox));
uilistbox->obj = obj;
uilistbox->listbox = GTK_LIST_BOX(listbox);
- uilistbox->getvalue = args.getvalue;
- uilistbox->onactivate = args.onactivate;
- uilistbox->onactivatedata = args.onactivatedata;
- uilistbox->onbuttonclick = args.onbuttonclick;
- uilistbox->onbuttonclickdata = args.onbuttonclickdata;
+ uilistbox->getvalue = args->getvalue;
+ uilistbox->getvaluedata = args->getvaluedata;
+ uilistbox->onactivate = args->onactivate;
+ uilistbox->onactivatedata = args->onactivatedata;
+ uilistbox->onbuttonclick = args->onbuttonclick;
+ uilistbox->onbuttonclickdata = args->onbuttonclickdata;
uilistbox->sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), 4);
uilistbox->sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_destroy;
uilistbox->sublists->collection.destructor_data = obj;
uilistbox->first_row = NULL;
- if(args.sublists) {
+ if(args->sublists) {
// static sublist initalization
- if(args.numsublists == 0 && args.sublists) {
- args.numsublists = INT_MAX;
+ if(args->numsublists == 0 && args->sublists) {
+ args->numsublists = INT_MAX;
}
- for(int i=0;inumsublists;i++) {
+ UiSubList sublist = args->sublists[i];
if(!sublist.varname && !sublist.value) {
break;
}
@@ -1799,13 +1868,13 @@
// fill items
ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
} else {
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.dynamic_sublist, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
if(var) {
UiList *list = var->value;
list->obj = uilistbox;
list->update = ui_listbox_dynamic_update;
- ui_listbox_dynamic_update(list, 0);
+ ui_listbox_dynamic_update(list, -1);
}
}
@@ -1821,7 +1890,7 @@
G_CALLBACK(ui_destroy_sourcelist),
uilistbox);
- if(args.onactivate) {
+ if(args->onactivate) {
g_signal_connect(
listbox,
"row-activated",
@@ -1838,6 +1907,15 @@
// unbind/free previous list vars
CxIterator i = cxListIterator(uilistbox->sublists);
cx_foreach(UiListBoxSubList *, s, i) {
+ // TODO: "unbind/free previous list vars" will also remove
+ // the widget list. This makes the widget optimization
+ // in ui_listbox_update_sublist pointless
+ // Is it actually possible to not recreate the whole list?
+ CxIterator r = cxListIterator(s->widgets);
+ cx_foreach(GtkWidget*, widget, r) {
+ LISTBOX_REMOVE(uilistbox->listbox, widget);
+ }
+
if(s->var) {
UiList *sl = s->var->value;
sl->obj = NULL;
@@ -1936,7 +2014,11 @@
void *elm = list->first(list);
while(elm) {
UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
- listbox->getvalue(sublist->userdata, elm, index, &item);
+ if(listbox->getvalue) {
+ listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata);
+ } else {
+ item.label = strdup(elm);
+ }
// create listbox item
GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index);
@@ -1987,7 +2069,7 @@
eventdata.sublist_index = sublist->index;
eventdata.row_index = data->value0;
eventdata.sublist_userdata = sublist->userdata;
- eventdata.row_data = ui_list_get(eventdata.list, eventdata.row_index);
+ eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
eventdata.event_data = data->customdata2;
UiEvent event;
@@ -1995,6 +2077,7 @@
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata = &eventdata;
+ event.eventdatatype = UI_EVENT_DATA_SUBLIST;
event.intval = data->value0;
event.set = ui_get_setop();
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/list.h
--- a/ui/gtk/list.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/list.h Sun Jul 20 22:04:39 2025 +0200
@@ -98,6 +98,7 @@
GtkListBox *listbox;
CxList *sublists; // contains UiListBoxSubList elements
ui_sublist_getvalue_func getvalue;
+ void *getvaluedata;
ui_callback onactivate;
void *onactivatedata;
ui_callback onbuttonclick;
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/menu.c
--- a/ui/gtk/menu.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/menu.c Sun Jul 20 22:04:39 2025 +0200
@@ -233,6 +233,20 @@
}
*/
+static void menuitem_list_remove_binding(void *obj) {
+ UiActiveMenuItemList *ls = obj;
+ UiList *list = ls->var->value;
+ CxList *bindings = list->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ if(cxListSize(bindings) == 0) {
+ cxListFree(bindings);
+ list->obj = NULL;
+ list->update = NULL;
+ }
+ }
+}
+
void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
const CxAllocator *a = obj->ctx->allocator;
@@ -247,21 +261,45 @@
ls->oldcount = 0;
ls->getvalue = il->getvalue;
- UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
- ls->list = var->value;
+ //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
+ ls->var = var;
+ if(var) {
+ UiList *list = var->value;
+ list->update = ui_menulist_update;
+ list->getselection = NULL;
+ list->setselection = NULL;
+
+ // It is possible, that the UiVar is from a global shared context,
+ // used by multiple windows. To support this usecase, the list->obj
+ // binding object is a list of all connected UiActiveMenuItemList.
+ CxList *bindings = list->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ list->obj = bindings;
+ }
+ cxListAdd(bindings, ls);
+
+ // The destruction of the toplevel obj must remove the menulist binding
+ uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+
+ ui_update_menuitem_list(ls);
+ }
ls->callback = il->callback;
ls->userdata = il->userdata;
-
- UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
- ls->list->observers = ui_obsvlist_add(ls->list->observers, observer);
- uic_list_register_observer_destructor(obj->ctx, ls->list, observer);
-
- ui_update_menuitem_list(NULL, ls);
+}
+
+void ui_menulist_update(UiList *list, int ignored) {
+ CxList *bindings = list->obj;
+ CxIterator i = cxListIterator(bindings);
+ cx_foreach(UiActiveMenuItemList *, ls, i) {
+ ui_update_menuitem_list(ls);
+ }
}
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
+void ui_update_menuitem_list(UiActiveMenuItemList *list) {
// remove old items
if(list->oldcount > 0) {
int i = 0;
@@ -276,7 +314,9 @@
}
}
- void* elm = ui_list_first(list->list);
+ UiList *ls = list->var->value;
+
+ void* elm = ui_list_first(ls);
if(elm) {
GtkWidget *widget = gtk_separator_menu_item_new();
gtk_menu_shell_insert(list->menu, widget, list->index);
@@ -312,7 +352,7 @@
event);
}
- elm = ui_list_next(list->list);
+ elm = ui_list_next(ls);
i++;
}
@@ -474,6 +514,7 @@
event->callback = i->callback;
event->value = 0;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
action,
@@ -506,6 +547,20 @@
}
+static void menuitem_list_remove_binding(void *obj) {
+ UiActiveGMenuItemList *ls = obj;
+ UiList *list = ls->var->value;
+ CxList *bindings = list->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ if(cxListSize(bindings) == 0) {
+ cxListFree(bindings);
+ list->obj = NULL;
+ list->update = NULL;
+ }
+ }
+}
+
void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
@@ -521,17 +576,34 @@
ls->oldcount = 0;
ls->getvalue = il->getvalue;
- UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
ls->var = var;
- UiList *list = var->value;
+ if(var) {
+ UiList *list = var->value;
+ list->update = ui_menulist_update;
+ list->getselection = NULL;
+ list->setselection = NULL;
+
+ // It is possible, that the UiVar is from a global shared context,
+ // used by multiple windows. To support this usecase, the list->obj
+ // binding object is a list of all connected UiActiveMenuItemList.
+ CxList *bindings = list->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ list->obj = bindings;
+ }
+ cxListAdd(bindings, ls);
+
+ // The destruction of the toplevel obj must remove the menulist binding
+ uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+
+ ui_update_gmenu_item_list(ls);
+ }
ls->callback = il->callback;
ls->userdata = il->userdata;
- UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls);
- list->observers = ui_obsvlist_add(list->observers, observer);
- uic_list_register_observer_destructor(obj->ctx, list, observer);
-
GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
snprintf(ls->action, 32, "win.%s", item->id);
@@ -542,6 +614,7 @@
event->userdata = il->userdata;
event->callback = il->callback;
event->customdata = var;
+ event->customint = 0;
event->value = 0;
g_signal_connect(
@@ -554,8 +627,6 @@
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
-
- ui_update_gmenu_item_list(NULL, ls);
}
void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
@@ -569,6 +640,7 @@
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
evt.eventdata = event->customdata;
+ evt.eventdatatype = event->customint;
evt.intval = intval;
event->callback(&evt, event->userdata);
}
@@ -583,12 +655,21 @@
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
evt.eventdata = ui_list_get(list, index);
+ evt.eventdatatype = UI_EVENT_DATA_LIST_ELM;
evt.intval = index;
event->callback(&evt, event->userdata);
}
-void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) {
+void ui_menulist_update(UiList *list, int ignored) {
+ CxList *bindings = list->obj;
+ CxIterator i = cxListIterator(bindings);
+ cx_foreach(UiActiveGMenuItemList *, ls, i) {
+ ui_update_gmenu_item_list(ls);
+ }
+}
+
+void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) {
// remove old items
for(int i=0;ioldcount;i++) {
g_menu_remove(list->menu, list->index);
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/menu.h
--- a/ui/gtk/menu.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/menu.h Sun Jul 20 22:04:39 2025 +0200
@@ -55,10 +55,10 @@
GtkMenuShell *menu;
int index;
int oldcount;
- UiList *list;
- ui_getvaluefunc getvalue;
- ui_callback callback;
- void *userdata;
+ UiVar *var;
+ ui_getvaluefunc getvalue;
+ ui_callback callback;
+ void *userdata;
};
void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj);
@@ -72,7 +72,8 @@
void add_checkitemnv_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj);
void add_menuitem_list_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj);
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_menuitem_list(UiActiveMenuItemList *list);
void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event);
void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event);
int64_t ui_checkitem_get(UiInteger *i);
@@ -108,7 +109,8 @@
void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event);
void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event);
-void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_gmenu_item_list(UiActiveGMenuItemList *list);
#endif
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/range.c
--- a/ui/gtk/range.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/range.c Sun Jul 20 22:04:39 2025 +0200
@@ -62,6 +62,7 @@
event->callback = f;
event->value = 0;
event->customdata = NULL;
+ event->customint = 0;
g_signal_connect(
G_OBJECT(scrollbar),
@@ -76,7 +77,7 @@
}
UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, scrollbar, FALSE);
+ ct->add(ct, scrollbar);
return scrollbar;
}
@@ -95,6 +96,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = event->value;
event->callback(&e, event->userdata);
return TRUE;
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/text.c
--- a/ui/gtk/text.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/text.c Sun Jul 20 22:04:39 2025 +0200
@@ -107,13 +107,13 @@
return buf;
}
-UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
+UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
UiObject* current = uic_current_obj(obj);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_TEXT);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_TEXT);
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_name_and_style(text_area, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, text_area, args->groups);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR);
g_signal_connect(
@@ -127,8 +127,8 @@
uitext->ctx = obj->ctx;
uitext->var = var;
uitext->last_selection_state = 0;
- uitext->onchange = args.onchange;
- uitext->onchangedata = args.onchangedata;
+ uitext->onchange = args->onchange;
+ uitext->onchangedata = args->onchangedata;
g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext);
@@ -155,8 +155,8 @@
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_area), 2);
// add
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, scroll_area, TRUE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, scroll_area);
// bind value
if(var) {
@@ -330,6 +330,7 @@
e.window = e.obj->window;
e.document = textarea->ctx->document;
e.eventdata = value;
+ e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
e.intval = 0;
e.set = ui_get_setop();
@@ -592,21 +593,21 @@
-static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs args) {
+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_name_and_style(textfield, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, textfield, args->groups);
UiObject* current = uic_current_obj(obj);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
UiTextField *uitext = malloc(sizeof(UiTextField));
uitext->obj = obj;
uitext->var = var;
- uitext->onchange = args.onchange;
- uitext->onchangedata = args.onchangedata;
- uitext->onactivate = args.onactivate;
- uitext->onactivatedata = args.onactivatedata;
+ uitext->onchange = args->onchange;
+ uitext->onchangedata = args->onchangedata;
+ uitext->onactivate = args->onactivate;
+ uitext->onactivatedata = args->onactivatedata;
g_signal_connect(
textfield,
@@ -614,10 +615,10 @@
G_CALLBACK(ui_textfield_destroy),
uitext);
- if(args.width > 0) {
+ if(args->width > 0) {
// TODO: gtk4
#if GTK_MAJOR_VERSION <= 3
- gtk_entry_set_width_chars(GTK_ENTRY(textfield), args.width);
+ gtk_entry_set_width_chars(GTK_ENTRY(textfield), args->width);
#endif
}
if(frameless) {
@@ -628,8 +629,8 @@
gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
}
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, textfield, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, textfield);
if(var) {
UiString *value = var->value;
@@ -647,7 +648,7 @@
value->obj = GTK_ENTRY(textfield);
}
- if(args.onchange || var) {
+ if(args->onchange || var) {
g_signal_connect(
textfield,
"changed",
@@ -655,7 +656,7 @@
uitext);
}
- if(args.onactivate) {
+ if(args->onactivate) {
g_signal_connect(
textfield,
"activate",
@@ -666,15 +667,15 @@
return textfield;
}
-UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) {
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
return create_textfield(obj, FALSE, FALSE, args);
}
-UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, TRUE, FALSE, args);
}
-UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, FALSE, TRUE, args);
}
@@ -691,6 +692,7 @@
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
e.eventdata = value;
+ e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
e.intval = 0;
e.set = ui_get_setop();
@@ -710,6 +712,7 @@
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = 0;
e.set = ui_get_setop();
textfield->onactivate(&e, textfield->onactivatedata);
@@ -807,6 +810,7 @@
evt.window = evt.obj->window;
evt.document = evt.obj->ctx->document;
evt.eventdata = elm->path;
+ evt.eventdatatype = UI_EVENT_DATA_STRING;
evt.intval = event->value0;
evt.set = ui_get_setop();
event->callback(&evt, event->userdata);
@@ -888,6 +892,7 @@
evt.window = obj->window;
evt.document = obj->ctx->document;
evt.eventdata = (char*)text;
+ evt.eventdatatype = UI_EVENT_DATA_STRING;
evt.intval = -1;
pathtf->onactivate(&evt, pathtf->onactivatedata);
}
@@ -915,22 +920,22 @@
return FALSE;
}
-UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
+UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
UiObject* current = uic_current_obj(obj);
UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
memset(pathtf, 0, sizeof(UiPathTextField));
pathtf->obj = obj;
- pathtf->getpathelm = args.getpathelm;
- pathtf->getpathelmdata = args.getpathelmdata;
- pathtf->onactivate = args.onactivate;
- pathtf->onactivatedata = args.onactivatedata;
- pathtf->ondragcomplete = args.ondragcomplete;
- pathtf->ondragcompletedata = args.ondragcompletedata;
- pathtf->ondragstart = args.ondragstart;
- pathtf->ondragstartdata = args.ondragstartdata;
- pathtf->ondrop = args.ondrop;
- pathtf->ondropdata = args.ondropsdata;
+ pathtf->getpathelm = args->getpathelm;
+ pathtf->getpathelmdata = args->getpathelmdata;
+ pathtf->onactivate = args->onactivate;
+ pathtf->onactivatedata = args->onactivatedata;
+ pathtf->ondragcomplete = args->ondragcomplete;
+ pathtf->ondragcompletedata = args->ondragcompletedata;
+ pathtf->ondragstart = args->ondragstart;
+ pathtf->ondragstartdata = args->ondragstartdata;
+ pathtf->ondrop = args->ondrop;
+ pathtf->ondropdata = args->ondropsdata;
if(!pathtf->getpathelm) {
pathtf->getpathelm = default_pathelm_func;
@@ -940,8 +945,8 @@
pathtf->stack = gtk_stack_new();
gtk_widget_set_name(pathtf->stack, "path-textfield-box");
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, pathtf->stack, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, pathtf->stack);
pathtf->entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
pathtf->entry = gtk_entry_new();
@@ -973,7 +978,7 @@
gtk_stack_set_visible_child(GTK_STACK(pathtf->stack), pathtf->entry_box);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = pathtf;
@@ -1076,22 +1081,22 @@
return bb;
}
-UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
+UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
UiObject* current = uic_current_obj(obj);
UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
memset(pathtf, 0, sizeof(UiPathTextField));
pathtf->obj = obj;
- pathtf->getpathelm = args.getpathelm;
- pathtf->getpathelmdata = args.getpathelmdata;
- pathtf->onactivate = args.onactivate;
- pathtf->onactivatedata = args.onactivatedata;
- pathtf->ondragcomplete = args.ondragcomplete;
- pathtf->ondragcompletedata = args.ondragcompletedata;
- pathtf->ondragstart = args.ondragstart;
- pathtf->ondragstartdata = args.ondragstartdata;
- pathtf->ondrop = args.ondrop;
- pathtf->ondropdata = args.ondropsdata;
+ pathtf->getpathelm = args->getpathelm;
+ pathtf->getpathelmdata = args->getpathelmdata;
+ pathtf->onactivate = args->onactivate;
+ pathtf->onactivatedata = args->onactivatedata;
+ pathtf->ondragcomplete = args->ondragcomplete;
+ pathtf->ondragcompletedata = args->ondragcompletedata;
+ pathtf->ondragstart = args->ondragstart;
+ pathtf->ondragstartdata = args->ondragstartdata;
+ pathtf->ondrop = args->ondrop;
+ pathtf->ondropdata = args->ondropsdata;
if(!pathtf->getpathelm) {
pathtf->getpathelm = default_pathelm_func;
@@ -1112,7 +1117,7 @@
G_CALLBACK(ui_path_textfield_destroy),
pathtf);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->add(current->container, eventbox, FALSE);
// hbox as parent for the GtkEntry and GtkButtonBox
@@ -1137,7 +1142,7 @@
G_CALLBACK(ui_path_textfield_key_press),
pathtf);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = pathtf;
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/toolbar.c
--- a/ui/gtk/toolbar.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/toolbar.c Sun Jul 20 22:04:39 2025 +0200
@@ -155,6 +155,7 @@
event->callback = item->args.onclick;
event->userdata = item->args.onclickdata;
event->customdata = NULL;
+ event->customint = 0;
event->value = 0;
g_signal_connect(
@@ -237,6 +238,7 @@
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = gtk_toggle_tool_button_get_active(widget);
if(event->callback) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/toolkit.c
--- a/ui/gtk/toolkit.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/toolkit.c Sun Jul 20 22:04:39 2025 +0200
@@ -66,6 +66,8 @@
static int scale_factor = 1;
+static UiBool exit_on_shutdown;
+
UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
uic_init_global_context();
@@ -110,8 +112,11 @@
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
-#ifndef UI_GTK2
+#ifdef UI_APPLICATION
static void app_startup(GtkApplication* app, gpointer userdata) {
if(startup_func) {
startup_func(NULL, startup_data);
@@ -119,8 +124,16 @@
}
static void app_activate(GtkApplication* app, gpointer userdata) {
- printf("activate\n");
+ //printf("activate\n");
}
+
+static void app_shutdown(GtkApplication *app, gpointer userdata) {
+ if(exit_func) {
+ exit_func(NULL, exit_data);
+ }
+ ui_app_save_settings();
+}
+
#endif
void ui_main() {
@@ -130,6 +143,7 @@
application_name ? application_name : "application1");
app = UI_APPLICATION_NEW(appid.ptr);
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
+ g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_application_run(G_APPLICATION (app), 0, NULL);
g_object_unref (app);
@@ -140,11 +154,14 @@
startup_func(NULL, startup_data);
}
gtk_main();
-#endif
if(exit_func) {
exit_func(NULL, exit_data);
}
- uic_store_app_properties();
+ ui_app_save_settings();
+#endif
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
#ifndef UI_GTK2
@@ -191,6 +208,7 @@
event.document = job->obj->ctx->document;
event.intval = 0;
event.eventdata = NULL;
+ event.eventdatatype = 0;
job->finish_callback(&event, job->finish_data);
free(job);
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/toolkit.h
--- a/ui/gtk/toolkit.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/toolkit.h Sun Jul 20 22:04:39 2025 +0200
@@ -131,6 +131,7 @@
ui_callback callback;
void *userdata;
int value;
+ int customint;
void *customdata;
} UiEventData;
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/webview.c
--- a/ui/gtk/webview.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/webview.c Sun Jul 20 22:04:39 2025 +0200
@@ -33,14 +33,14 @@
#ifdef UI_WEBVIEW
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs args) {
+UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *webview = webkit_web_view_new();
- ui_set_name_and_style(webview, args.name, args.style_class);
+ ui_set_name_and_style(webview, args->name, args->style_class);
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC);
+ UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
if(var) {
WebViewData *data = malloc(sizeof(WebViewData));
memset(data, 0, sizeof(WebViewData));
@@ -59,9 +59,9 @@
}
}
- ui_set_widget_groups(obj->ctx, webview, args.groups);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, webview, FALSE);
+ ui_set_widget_groups(obj->ctx, webview, args->groups);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, webview);
return webview;
}
@@ -115,7 +115,14 @@
const char *mimetype,
const char *encoding)
{
+ WebViewData *data0 = g->obj;
+ if(!data0) {
+ return;
+ }
+
WebViewData data;
+ memset(&data, 0, sizeof(WebViewData));
+ data.webview = data0->webview;
data.uri = (char*)uri;
data.content = (char*)content;
data.contentlength = contentlength;
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/widget.c
--- a/ui/gtk/widget.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/widget.c Sun Jul 20 22:04:39 2025 +0200
@@ -31,13 +31,13 @@
#include "../common/object.h"
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
UiObject* current = uic_current_obj(obj);
UIWIDGET widget = create_widget(obj, args, userdata);
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, widget, FALSE);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, widget);
return widget;
}
@@ -47,7 +47,7 @@
GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
ui_set_name_and_style(widget, args->name, args->style_class);
UI_APPLY_LAYOUT1(current, (*args));
- current->container->add(current->container, widget, FALSE);
+ current->container->add(current->container, widget);
return widget;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/gtk/window.c
--- a/ui/gtk/window.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/gtk/window.c Sun Jul 20 22:04:39 2025 +0200
@@ -102,9 +102,7 @@
#endif
static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool simple) {
- CxMempool *mp = cxMempoolCreateSimple(256);
- UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
- obj->ref = 0;
+ UiObject *obj = uic_object_new_toplevel();
#ifdef UI_LIBADWAITA
obj->widget = adw_application_window_new(ui_get_application());
@@ -114,8 +112,6 @@
obj->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
#endif
-
- obj->ctx = uic_context(obj, mp);
obj->window = window_data;
#if GTK_CHECK_VERSION(4, 0, 0)
@@ -316,6 +312,8 @@
evt.document = evt.obj->ctx->document;
evt.window = evt.obj->window;
evt.eventdata = NULL;
+ evt.eventdatatype = 0;
+ evt.eventdatatype = 0;
evt.intval = 0;
if(!strcmp(response, "btn1")) {
@@ -327,6 +325,7 @@
if(data->customdata) {
GtkWidget *entry = data->customdata;
evt.eventdata = (void*)ENTRY_GET_TEXT(GTK_ENTRY(entry));
+ evt.eventdatatype = UI_EVENT_DATA_STRING;
}
if(data->callback) {
@@ -334,37 +333,39 @@
}
}
-void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
- AdwDialog *dialog = adw_alert_dialog_new(args.title, args.content);
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
+ AdwDialog *dialog = adw_alert_dialog_new(args->title, args->content);
UiEventData *event = malloc(sizeof(UiEventData));
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->customdata = NULL;
+ event->customint = 0;
event->value = 0;
event->obj = parent;
- if(args.button1_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args.button1_label);
+ if(args->button1_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args->button1_label);
}
- if(args.button2_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args.button2_label);
+ if(args->button2_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args->button2_label);
}
- if(args.closebutton_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args.closebutton_label);
+ if(args->closebutton_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args->closebutton_label);
adw_alert_dialog_set_close_response(ADW_ALERT_DIALOG(dialog), "close");
}
GtkWidget *entry = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
entry = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(entry, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(entry, args->input_value);
}
adw_alert_dialog_set_extra_child(ADW_ALERT_DIALOG(dialog), entry);
event->customdata = entry;
+ event->customint = 0;
}
g_signal_connect(
@@ -415,41 +416,41 @@
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
GtkWidget *dialog_w = GTK_WIDGET(dialog);
- if(args.title) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
- if(args.button1_label) {
- gtk_dialog_add_button(dialog, args.button1_label, 1);
+ if(args->button1_label) {
+ gtk_dialog_add_button(dialog, args->button1_label, 1);
}
- if(args.button2_label) {
- gtk_dialog_add_button(dialog, args.button2_label, 2);
+ if(args->button2_label) {
+ gtk_dialog_add_button(dialog, args->button2_label, 2);
}
- if(args.closebutton_label) {
- gtk_dialog_add_button(dialog, args.closebutton_label, 0);
+ if(args->closebutton_label) {
+ gtk_dialog_add_button(dialog, args->closebutton_label, 0);
}
GtkWidget *content_area = gtk_dialog_get_content_area(dialog);
- if(args.content) {
- GtkWidget *label = gtk_label_new(args.content);
+ if(args->content) {
+ GtkWidget *label = gtk_label_new(args->content);
BOX_ADD(content_area, label);
}
GtkWidget *textfield = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
textfield = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(textfield, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(textfield, args->input_value);
}
BOX_ADD(content_area, textfield);
}
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = parent;
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->value = 0;
event->customdata = textfield;
@@ -521,6 +522,7 @@
flist.files = NULL;
flist.nfiles = 0;
evt.eventdata = &flist;
+ evt.eventdatatype = UI_EVENT_DATA_FILE_LIST;
if(selection) {
flist = listmodel2filelist(selection);
@@ -555,6 +557,7 @@
event->callback = file_selected_callback;
event->userdata = cbdata;
event->customdata = NULL;
+ event->customint = 0;
event->value = mode;
event->obj = obj;
@@ -746,38 +749,36 @@
-UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
+UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
GtkWidget *dialog = DIALOG_NEW();
- if(args.width > 0 || args.height > 0) {
+ if(args->width > 0 || args->height > 0) {
gtk_window_set_default_size(
GTK_WINDOW(dialog),
- args.width,
- args.height);
+ args->width,
+ args->height);
}
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget));
- if(args.modal != UI_OFF) {
+ if(args->modal != UI_OFF) {
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
}
- CxMempool *mp = cxMempoolCreateSimple(256);
- UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
- obj->ctx = uic_context(obj, mp);
+ UiObject *obj = uic_object_new_toplevel();
obj->widget = dialog;
obj->ref = 0;
obj->destroy = ui_window_widget_destroy;
nwindows++;
- if(args.title != NULL) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title != NULL) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
#if ! GTK_CHECK_VERSION(4, 10, 0)
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = obj;
- event->userdata = args.onclickdata;
- event->callback = args.onclick;
+ event->userdata = args->onclickdata;
+ event->callback = args->onclick;
event->value = 0;
event->customdata = NULL;
@@ -815,44 +816,44 @@
GtkWidget *content_vbox = ui_gtk_vbox_new(0);
obj->container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
- if(args.lbutton1 || args.lbutton2 || args.rbutton3 || args.rbutton4) {
+ if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) {
#if GTK_CHECK_VERSION(3, 10, 0)
- if(args.titlebar_buttons != UI_OFF) {
+ if(args->titlebar_buttons != UI_OFF) {
GtkWidget *headerbar = gtk_header_bar_new();
gtk_window_set_titlebar(GTK_WINDOW(dialog), headerbar);
- if(args.show_closebutton == UI_OFF) {
+ if(args->show_closebutton == UI_OFF) {
HEADERBAR_SHOW_CLOSEBUTTON(headerbar, FALSE);
}
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton3) {
- GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
@@ -870,18 +871,18 @@
GtkWidget *widget = ui_box_set_margin(grid, 16);
gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
@@ -889,18 +890,18 @@
GtkWidget *space = gtk_label_new(NULL);
gtk_widget_set_hexpand(space, TRUE);
gtk_grid_attach(GTK_GRID(grid), space, 2, 0, 1, 1);
- if(args.rbutton3) {
- GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/Makefile
--- a/ui/motif/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -27,7 +27,10 @@
#
$(MOTIF_OBJPRE)%.o: motif/%.c
- $(CC) -o $@ -c -I../ucx $(CFLAGS) $(TK_CFLAGS) $<
+ $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
$(UI_LIB): $(OBJ)
$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
+
+$(UI_SHLIB): $(OBJ)
+ $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/button.c
--- a/ui/motif/button.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/button.c Sun Jul 20 22:04:39 2025 +0200
@@ -41,7 +41,7 @@
#include
-UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) {
+UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
Arg xargs[16];
int n = 0;
@@ -51,22 +51,22 @@
Widget parent = ctn->prepare(ctn, xargs, &n);
XmString label = NULL;
- if(args.label) {
- label = XmStringCreateLocalized((char*)args.label);
+ if(args->label) {
+ label = XmStringCreateLocalized((char*)args->label);
XtSetArg(xargs[n], XmNlabelString, label); n++;
}
- char *name = args.name ? (char*)args.name : "button";
+ char *name = args->name ? (char*)args->name : "button";
Widget button = XmCreatePushButton(parent, name, xargs, n);
XtManageChild(button);
ctn->add(ctn, button);
- ui_set_widget_groups(obj->ctx, button, args.groups);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
- if(args.onclick) {
+ if(args->onclick) {
UiEventData *eventdata = malloc(sizeof(UiEventData));
- eventdata->callback = args.onclick;
- eventdata->userdata = args.onclickdata;
+ eventdata->callback = args->onclick;
+ eventdata->userdata = args->onclickdata;
eventdata->obj = obj;
eventdata->value = 0;
XtAddCallback(
@@ -96,7 +96,7 @@
event->callback(&e, event->userdata);
}
-UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) {
Arg xargs[16];
int n = 0;
@@ -108,25 +108,25 @@
XtSetArg(xargs[n], XmNindicatorOn, False); n++;
XmString label = NULL;
- if(args.label) {
- label = XmStringCreateLocalized((char*)args.label);
+ if(args->label) {
+ label = XmStringCreateLocalized((char*)args->label);
XtSetArg(xargs[n], XmNlabelString, label); n++;
}
- char *name = args.name ? (char*)args.name : "togglebutton";
+ char *name = args->name ? (char*)args->name : "togglebutton";
Widget button = XmCreateToggleButton(parent, name, xargs, n);
XtManageChild(button);
ctn->add(ctn, button);
- ui_set_widget_groups(obj->ctx, button, args.groups);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
- ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group);
+ ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->enable_group);
XmStringFree(label);
return button;
}
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
Arg xargs[16];
int n = 0;
@@ -136,25 +136,25 @@
Widget parent = ctn->prepare(ctn, xargs, &n);
XmString label = NULL;
- if(args.label) {
- label = XmStringCreateLocalized((char*)args.label);
+ if(args->label) {
+ label = XmStringCreateLocalized((char*)args->label);
XtSetArg(xargs[n], XmNlabelString, label); n++;
}
- char *name = args.name ? (char*)args.name : "button";
+ char *name = args->name ? (char*)args->name : "button";
Widget button = XmCreateToggleButton(parent, name, xargs, n);
XtManageChild(button);
ctn->add(ctn, button);
- ui_set_widget_groups(obj->ctx, button, args.groups);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
- ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group);
+ ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->enable_group);
XmStringFree(label);
return button;
}
-UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
return ui_checkbox_create(obj, args);
}
@@ -173,6 +173,7 @@
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = XmToggleButtonGetState(w);
e.set = ui_get_setop();
@@ -282,6 +283,7 @@
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata = value;
+ e.eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
e.intval = v;
e.set = ui_get_setop();
@@ -343,7 +345,7 @@
event);
}
-UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) {
Arg xargs[16];
int n = 0;
@@ -353,19 +355,19 @@
Widget parent = ctn->prepare(ctn, xargs, &n);
XtSetArg(xargs[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++;
XmString label = NULL;
- if(args.label) {
- label = XmStringCreateLocalized((char*)args.label);
+ if(args->label) {
+ label = XmStringCreateLocalized((char*)args->label);
XtSetArg(xargs[n], XmNlabelString, label); n++;
}
- char *name = args.name ? (char*)args.name : "button";
+ char *name = args->name ? (char*)args->name : "button";
Widget button = XmCreateToggleButton(parent, name, xargs, n);
XtManageChild(button);
ctn->add(ctn, button);
- ui_set_widget_groups(obj->ctx, button, args.groups);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *value = var->value;
CxList *rb = value->obj;
@@ -396,11 +398,11 @@
// other buttons in the radio button group
UiVarEventData *event = malloc(sizeof(UiVarEventData));
event->obj = obj;
- event->callback = args.onchange;
- event->userdata = args.onchangedata;
+ event->callback = args->onchange;
+ event->userdata = args->onchangedata;
event->observers = NULL;
event->var = var;
- event->value = args.enable_group;
+ event->value = args->enable_group;
XtAddCallback(
button,
XmNvalueChangedCallback,
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/container.c
--- a/ui/motif/container.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/container.c Sun Jul 20 22:04:39 2025 +0200
@@ -43,7 +43,7 @@
/* ---------------------------- Box Container ---------------------------- */
-static UIWIDGET box_create(UiObject *obj, UiContainerArgs args, UiBoxOrientation orientation) {
+static UIWIDGET box_create(UiObject *obj, UiContainerArgs *args, UiBoxOrientation orientation) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
@@ -51,13 +51,13 @@
int n = 0;
if(orientation == UI_BOX_VERTICAL) {
- //XtSetArg(xargs[n], gridRowSpacing, args.spacing); n++;
+ //XtSetArg(xargs[n], gridRowSpacing, args->spacing); n++;
} else {
- //XtSetArg(xargs[n], gridColumnSpacing, args.spacing); n++;
+ //XtSetArg(xargs[n], gridColumnSpacing, args->spacing); n++;
}
Widget parent = ctn->prepare(ctn, xargs, &n);
- Widget grid = XtCreateManagedWidget(args.name ? args.name : "boxcontainer", gridClass, parent, xargs, n);
+ Widget grid = XtCreateManagedWidget(args->name ? args->name : "boxcontainer", gridClass, parent, xargs, n);
ctn->add(ctn, grid);
UiContainerX *container = ui_box_container(obj, grid, orientation);
@@ -67,12 +67,12 @@
}
// public
-UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
return box_create(obj, args, UI_BOX_VERTICAL);
}
// public
-UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
return box_create(obj, args, UI_BOX_HORIZONTAL);
}
@@ -129,7 +129,7 @@
/* ---------------------------- Grid Container ---------------------------- */
// public
-UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
Arg xargs[16];
int n = 0;
@@ -137,13 +137,13 @@
UI_APPLY_LAYOUT(ctn->layout, args);
Widget parent = ctn->prepare(ctn, xargs, &n);
- XtSetArg(xargs[n], gridMargin, args.margin); n++;
- XtSetArg(xargs[n], gridColumnSpacing, args.columnspacing); n++;
- XtSetArg(xargs[n], gridRowSpacing, args.rowspacing); n++;
- Widget grid = XtCreateManagedWidget(args.name ? args.name : "gridcontainer", gridClass, parent, xargs, n);
+ XtSetArg(xargs[n], gridMargin, args->margin); n++;
+ XtSetArg(xargs[n], gridColumnSpacing, args->columnspacing); n++;
+ XtSetArg(xargs[n], gridRowSpacing, args->rowspacing); n++;
+ Widget grid = XtCreateManagedWidget(args->name ? args->name : "gridcontainer", gridClass, parent, xargs, n);
ctn->add(ctn, grid);
- UiContainerX *container = ui_grid_container(obj, grid, args.def_hexpand, args.def_vexpand, args.def_hfill, args.def_vfill);
+ UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
uic_object_push_container(obj, container);
return grid;
@@ -308,7 +308,7 @@
}
}
-UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs args) {
+UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) {
Arg xargs[16];
int n = 0;
@@ -321,7 +321,7 @@
// - content (Frame)
UiMotifTabView *tabview = malloc(sizeof(UiMotifTabView));
memset(tabview, 0, sizeof(UiMotifTabView));
- char *name = args.name ? (char*)args.name : "tabview";
+ char *name = args->name ? (char*)args->name : "tabview";
XtSetArg(xargs[n], XmNuserData, tabview); n++;
Widget parent = ctn->prepare(ctn, xargs, &n);
Widget form = XmCreateForm(parent, name, xargs, n);
@@ -354,8 +354,8 @@
tabview->form = form;
tabview->tabbar = tabbar;
tabview->content = content;
- tabview->tabview = args.tabview;
- tabview->subcontainer = args.subcontainer;
+ tabview->tabview = args->tabview;
+ tabview->subcontainer = args->subcontainer;
tabview->select = ui_motif_tabview_select;
tabview->add = ui_motif_tabview_add_tab;
tabview->remove = ui_motif_tabview_remove;
@@ -369,7 +369,7 @@
ct->container.add = ui_tabview_container_add;
ct->tabview = tabview;
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *i = var->value;
i->obj = tabview;
@@ -411,7 +411,7 @@
}
- Widget child = ui_vbox_create(obj, (UiContainerArgs) { 0 });
+ Widget child = ui_vbox_create(obj, &(UiContainerArgs) { 0 });
if(tabview->current) {
XtUnmanageChild(child);
} else {
@@ -605,7 +605,7 @@
return (UiContainerX*)ctn;
}
-UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/container.h
--- a/ui/motif/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -39,14 +39,14 @@
#endif
#define UI_APPLY_LAYOUT(layout, args) \
- layout.fill = args.fill; \
- layout.hexpand = args.hexpand; \
- layout.vexpand = args.vexpand; \
- layout.hfill = args.hfill; \
- layout.vfill = args.vfill; \
- layout.override_defaults = args.override_defaults; \
- layout.colspan = args.colspan; \
- layout.rowspan = args.rowspan
+ layout.fill = args->fill; \
+ layout.hexpand = args->hexpand; \
+ layout.vexpand = args->vexpand; \
+ layout.hfill = args->hfill; \
+ layout.vfill = args->vfill; \
+ layout.override_defaults = args->override_defaults; \
+ layout.colspan = args->colspan; \
+ layout.rowspan = args->rowspan
typedef enum UiBoxOrientation UiBoxOrientation;
@@ -65,7 +65,7 @@
typedef struct UiLayout UiLayout;
struct UiLayout {
- UiTri fill;
+ UiBool fill;
UiBool newline;
char *label;
UiBool hexpand;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/image.c
--- a/ui/motif/image.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/image.c Sun Jul 20 22:04:39 2025 +0200
@@ -6,3 +6,12 @@
#include "image.h"
+
+
+void ui_image_ref(UIIMAGE img) {
+ // TODO
+}
+
+void ui_image_unref(UIIMAGE img) {
+ // TODO
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/label.c
--- a/ui/motif/label.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/label.c Sun Jul 20 22:04:39 2025 +0200
@@ -36,7 +36,7 @@
#include "Grid.h"
-static UIWIDGET label_create(UiObject *obj, UiLabelArgs args, int align) {
+static UIWIDGET label_create(UiObject *obj, UiLabelArgs *args, int align) {
Arg xargs[16];
int n = 0;
@@ -47,12 +47,12 @@
XtSetArg(xargs[n], XmNalignment, align); n++;
XmString label = NULL;
- if(args.label) {
- label = XmStringCreateLocalized((char*)args.label);
+ if(args->label) {
+ label = XmStringCreateLocalized((char*)args->label);
XtSetArg(xargs[n], XmNlabelString, label); n++;
}
- char *name = args.name ? (char*)args.name : "label";
+ char *name = args->name ? (char*)args->name : "label";
Widget w = XmCreateLabel(parent, name, xargs, n);
XtManageChild(w);
ctn->add(ctn, w);
@@ -61,15 +61,15 @@
return w;
}
-UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs args) {
+UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs *args) {
return label_create(obj, args, XmALIGNMENT_CENTER);
}
-UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) {
+UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args) {
return label_create(obj, args, XmALIGNMENT_BEGINNING);
}
-UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args) {
+UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
return label_create(obj, args, XmALIGNMENT_END);
}
@@ -103,7 +103,7 @@
XFillRectangle(dp, w, pb->gc, 0, 0, valueW, widget->core.height);
}
-UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args) {
+UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
Arg xargs[16];
int n = 0;
@@ -112,7 +112,7 @@
Widget parent = ctn->prepare(ctn, xargs, &n);
- char *name = args.name ? (char*)args.name : "progressbar";
+ char *name = args->name ? (char*)args->name : "progressbar";
Widget frame = XmCreateFrame(parent, name, xargs, n);
// create a button and get some informations about the height, shadow, highlight, ....
@@ -137,12 +137,12 @@
Widget drawingArea = XmCreateDrawingArea(frame, "progressbar_drawingarea", xargs, n);
XtManageChild(drawingArea);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_DOUBLE);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_DOUBLE);
UiProgressBar *progressbarData = malloc(sizeof(UiProgressBar));
progressbarData->widget = drawingArea;
- progressbarData->min = args.min;
- progressbarData->max = args.max == 0 ? 100 : args.max;
+ progressbarData->min = args->min;
+ progressbarData->max = args->max == 0 ? 100 : args->max;
progressbarData->value = 50;
progressbarData->var = var;
progressbarData->color = highlightColor;
@@ -186,7 +186,7 @@
}
-UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args) {
+UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args) {
Arg xargs[16];
int n = 0;
@@ -200,12 +200,12 @@
XtSetArg(xargs[n], XmNalignment, XmALIGNMENT_END); n++;
XtSetArg(xargs[n], gridMinWidth, 40); n++;
- char *name = args.name ? (char*)args.name : "progresss_spinner";
+ char *name = args->name ? (char*)args->name : "progresss_spinner";
Widget w = XmCreateLabel(parent, name, xargs, n);
XtManageChild(w);
ctn->add(ctn, w);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *value = var->value;
value->obj = w;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/list.c
--- a/ui/motif/list.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/list.c Sun Jul 20 22:04:39 2025 +0200
@@ -34,36 +34,61 @@
#include "list.h"
#include "../common/object.h"
-UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) {
+static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
+ return getvalue(elm, col);
+}
+
+/*
+static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
+ if(model->getvalue2) {
+ return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
+ } else if(model->getvalue) {
+ return model->getvalue(elm, col);
+ }
+ return NULL;
+}
+*/
+
+UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args) {
Arg xargs[16];
int n = 0;
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- if(args.multiselection) {
+ if(args->multiselection) {
XtSetArg(xargs[n], XmNselectionPolicy, XmEXTENDED_SELECT); n++;
} else {
XtSetArg(xargs[n], XmNselectionPolicy, XmSINGLE_SELECT); n++;
}
- char *name = args.name ? (char*)args.name : "listview";
+ char *name = args->name ? (char*)args->name : "listview";
Widget parent = ctn->prepare(ctn, xargs, &n);
Widget widget = XmCreateScrolledList(parent, name, xargs, n);
XtManageChild(widget);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
UiListView *listview = malloc(sizeof(UiListView));
memset(listview, 0, sizeof(UiListView));
listview->obj = obj;
listview->widget = widget;
- listview->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+ if(args->getvalue2) {
+ listview->getvalue = args->getvalue2;
+ listview->getvaluedata = args->getvalue2data;
+ } else if(args->getvalue) {
+ listview->getvalue = getvalue_wrapper;
+ listview->getvaluedata = args->getvalue;
+ } else {
+ listview->getvalue = getvalue_wrapper;
+ listview->getvaluedata = ui_strmodel_getvalue;
+ }
listview->var = var;
- listview->onactivate = args.onactivate;
- listview->onactivatedata = args.onactivatedata;
- listview->onselection = args.onselection;
- listview->onselectiondata = args.onselectiondata;
+ listview->onactivate = args->onactivate;
+ listview->onactivatedata = args->onactivatedata;
+ listview->onselection = args->onselection;
+ listview->onselectiondata = args->onselectiondata;
if(var) {
UiList *list = var->value;
@@ -109,6 +134,7 @@
event.window = obj->window;
event.document = obj->ctx->document;
event.eventdata = &sel;
+ event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
event.intval = sel.count > 0 ? sel.rows[0] : -1;
callback(&event, userdata);
}
@@ -139,13 +165,17 @@
}
}
-static XmStringTable create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count) {
+static XmStringTable create_stringlist(UiList *list, ui_getvaluefunc2 getvalue, void *getvaluedata, int *count) {
int num = list->count(list);
XmStringTable items = (XmStringTable)XtMalloc(num * sizeof(XmString));
void *data = list->first(list);
for(int i=0;inext(list);
}
@@ -160,6 +190,7 @@
XmStringTable items = create_stringlist(
list,
listview->getvalue,
+ listview->getvaluedata,
&count);
XtVaSetValues(
@@ -206,18 +237,20 @@
UiListView *listview,
XmComboBoxCallbackStruct *cb)
{
- UiListSelection sel = { 0, NULL };
- if(cb->item_position > 0) {
- sel.count = 1;
- sel.rows = malloc(sizeof(int));
- sel.rows[0] = cb->item_position-1;
+ int index = cb->item_position;
+ void *elm = NULL;
+ if(listview->var) {
+ UiList *list = listview->var->value;
+ elm = ui_list_get(list, index);
}
+
UiEvent event;
event.obj = listview->obj;
event.window = event.obj->window;
event.document = event.obj->ctx->document;
- event.eventdata = &sel;
- event.intval = 0;
+ event.eventdata = elm;
+ event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
+ event.intval = index;
if(listview->onactivate) {
listview->onactivate(&event, listview->onactivatedata);
}
@@ -226,30 +259,39 @@
}
}
-UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args) {
+UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args) {
Arg xargs[16];
int n = 0;
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- char *name = args.name ? (char*)args.name : "dropdown";
+ char *name = args->name ? (char*)args->name : "dropdown";
Widget parent = ctn->prepare(ctn, xargs, &n);
Widget widget = XmCreateDropDownList(parent, name, xargs, n);
XtManageChild(widget);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.list, args.varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
UiListView *listview = malloc(sizeof(UiListView));
memset(listview, 0, sizeof(UiListView));
listview->obj = obj;
listview->widget = widget;
- listview->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+ if(args->getvalue2) {
+ listview->getvalue = args->getvalue2;
+ listview->getvaluedata = args->getvalue2data;
+ } else if(args->getvalue) {
+ listview->getvalue = getvalue_wrapper;
+ listview->getvaluedata = args->getvalue;
+ } else {
+ listview->getvalue = getvalue_wrapper;
+ listview->getvaluedata = ui_strmodel_getvalue;
+ }
listview->var = var;
- listview->onactivate = args.onactivate;
- listview->onactivatedata = args.onactivatedata;
- listview->onselection = args.onselection;
- listview->onselectiondata = args.onselectiondata;
+ listview->onactivate = args->onactivate;
+ listview->onactivatedata = args->onactivatedata;
+ listview->onselection = args->onselection;
+ listview->onselectiondata = args->onselectiondata;
if(var) {
UiList *list = var->value;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/list.h
--- a/ui/motif/list.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/list.h Sun Jul 20 22:04:39 2025 +0200
@@ -42,7 +42,8 @@
Widget widget;
UiVar *var;
UiModel* model;
- ui_getvaluefunc getvalue;
+ ui_getvaluefunc2 getvalue;
+ void *getvaluedata;
UiListSelection current_selection;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/menu.c
--- a/ui/motif/menu.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/menu.c Sun Jul 20 22:04:39 2025 +0200
@@ -202,6 +202,20 @@
ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0);
}
+static void menuitem_list_remove_binding(void *obj) {
+ UiActiveMenuItemList *ls = obj;
+ UiList *list = ls->var->value;
+ CxList *bindings = list->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ if(cxListSize(bindings) == 0) {
+ cxListFree(bindings);
+ list->obj = NULL;
+ list->update = NULL;
+ }
+ }
+}
+
void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
const CxAllocator *a = obj->ctx->allocator;
@@ -218,17 +232,40 @@
ls->userdata = il->userdata;
ls->addseparator = il->addseparator;
- ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); //uic_widget_var(obj->ctx, obj->ctx, NULL, il->varname, UI_VAR_LIST);
- UiList *list = ls->var->value;
-
- UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
- list->observers = ui_obsvlist_add(list->observers, observer);
- uic_list_register_observer_destructor(obj->ctx, list, observer);
-
- ui_update_menuitem_list(NULL, ls);
+ //ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ ls->var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
+ if(ls->var) {
+ UiList *list = ls->var->value;
+ list->update = ui_menulist_update;
+ list->getselection = NULL;
+ list->setselection = NULL;
+
+ // It is possible, that the UiVar is from a global shared context,
+ // used by multiple windows. To support this usecase, the list->obj
+ // binding object is a list of all connected UiActiveMenuItemList.
+ CxList *bindings = list->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(ls->var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ list->obj = bindings;
+ }
+ cxListAdd(bindings, ls);
+
+ // The destruction of the toplevel obj must remove the menulist binding
+ uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+
+ ui_update_menuitem_list(ls);
+ }
}
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
+void ui_menulist_update(UiList *list, int ignored) {
+ CxList *bindings = list->obj;
+ CxIterator i = cxListIterator(bindings);
+ cx_foreach(UiActiveMenuItemList *, ls, i) {
+ ui_update_menuitem_list(ls);
+ }
+}
+
+void ui_update_menuitem_list(UiActiveMenuItemList *list) {
XmString s = NULL;
Arg args[4];
int n;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/menu.h
--- a/ui/motif/menu.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/menu.h Sun Jul 20 22:04:39 2025 +0200
@@ -64,7 +64,8 @@
void add_checkitemnv_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj);
void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj);
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_menuitem_list(UiActiveMenuItemList *list);
#ifdef __cplusplus
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/text.c
--- a/ui/motif/text.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/text.c Sun Jul 20 22:04:39 2025 +0200
@@ -38,7 +38,7 @@
/* ------------------------------ Text Area ------------------------------ */
-UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
+UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
Arg xargs[16];
int n = 0;
@@ -48,12 +48,12 @@
UI_APPLY_LAYOUT(ctn->layout, args);
Widget parent = ctn->prepare(ctn, xargs, &n);
- char *name = args.name ? (char*)args.name : "textarea";
+ char *name = args->name ? (char*)args->name : "textarea";
XtSetArg(xargs[n], XmNwidth, 100); n++;
Widget widget = XmCreateScrolledText(parent, name, xargs, n);
XtManageChild(widget);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_TEXT);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT);
UiTextArea *textarea = malloc(sizeof(UiTextArea));
memset(textarea, 0, sizeof(UiTextArea));
@@ -68,6 +68,9 @@
value->value.ptr = NULL;
}
+ value->save = ui_textarea_save;
+ value->restore = ui_textarea_restore;
+ value->destroy = ui_textarea_text_destroy;
value->set = ui_textarea_set;
value->get = ui_textarea_get;
value->getsubstr = ui_textarea_getsubstr;
@@ -79,8 +82,8 @@
value->value.ptr = NULL;
value->obj = widget;
- if(!value->undomgr) {
- value->undomgr = ui_create_undomgr();
+ if(!value->data2) {
+ value->data2 = ui_create_undomgr();
}
XtAddCallback(
@@ -103,6 +106,25 @@
return str;
}
+void ui_textarea_save(UiText *text) {
+ (void)ui_textarea_get(text);
+}
+
+void ui_textarea_restore(UiText *text) {
+ if(text->value.ptr) {
+ ui_textarea_set(text, text->value.ptr);
+ }
+}
+
+void ui_textarea_text_destroy(UiText *text) {
+ if(text->value.free) {
+ text->value.free(text->value.ptr);
+ }
+ if(text->data2) {
+ ui_destroy_undomgr(text->data2);
+ }
+}
+
void ui_textarea_set(UiText *text, const char *str) {
XmTextSetString(text->obj, (char*)str);
if(text->value.ptr) {
@@ -201,13 +223,13 @@
// TODO: bug, fix
return;
}
- if(!value->undomgr) {
- value->undomgr = ui_create_undomgr();
+ if(!value->data2) {
+ value->data2 = ui_create_undomgr();
}
XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data;
int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE;
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
if(!mgr->event) {
return;
}
@@ -307,7 +329,7 @@
void ui_text_undo(UiText *value) {
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
if(mgr->cur) {
UiTextBufOp *op = mgr->cur;
@@ -328,7 +350,7 @@
}
void ui_text_redo(UiText *value) {
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
UiTextBufOp *elm = NULL;
if(mgr->cur) {
@@ -361,7 +383,7 @@
/* ------------------------------ Text Field ------------------------------ */
-static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs args, int frameless, int password) {
+static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, int frameless, int password) {
Arg xargs[16];
int n = 0;
@@ -377,13 +399,13 @@
UI_APPLY_LAYOUT(ctn->layout, args);
Widget parent = ctn->prepare(ctn, xargs, &n);
- char *name = args.name ? (char*)args.name : "textfield";
+ char *name = args->name ? (char*)args->name : "textfield";
Widget textfield = XmCreateTextField(parent, name, xargs, n);
XtManageChild(textfield);
- ui_set_widget_groups(obj->ctx, textfield, args.groups);
+ ui_set_widget_groups(obj->ctx, textfield, args->groups);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
UiString *value = (UiString*)var->value;
value->obj = textfield;
@@ -398,20 +420,22 @@
return textfield;
}
-UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) {
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, FALSE, FALSE);
}
-UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, TRUE, FALSE);
}
-UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, FALSE, FALSE);
}
char* ui_textfield_get(UiString *str) {
- str->value.free(str->value.ptr);
+ if(str->value.free) {
+ str->value.free(str->value.ptr);
+ }
char *value = XmTextFieldGetString(str->obj);
str->value.ptr = value;
str->value.free = (ui_freefunc)XtFree;
@@ -420,8 +444,10 @@
void ui_textfield_set(UiString *str, const char *value) {
XmTextFieldSetString(str->obj, (void*)value);
+ if(str->value.free) {
+ str->value.free(str->value.ptr);
+ }
str->value.ptr = NULL;
- str->value.free(str->value.ptr);
}
@@ -935,11 +961,12 @@
evt.window = evt.obj->window;
evt.document = evt.obj->ctx->document;
evt.eventdata = path;
+ evt.eventdatatype = UI_EVENT_DATA_STRING;
evt.intval = index;
event->callback(&evt, event->userdata);
}
-UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
+UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
Arg xargs[16];
int n = 0;
@@ -951,18 +978,18 @@
PathBar *pathbar = CreatePathBar(parent, xargs, n);
- if(!args.getpathelm) {
+ if(!args->getpathelm) {
pathbar->getpathelm= default_pathelm_func;
} else {
- pathbar->getpathelm = args.getpathelm;
- pathbar->getpathelmdata = args.getpathelmdata;
+ pathbar->getpathelm = args->getpathelm;
+ pathbar->getpathelmdata = args->getpathelmdata;
}
XtManageChild(pathbar->widget);
ctn->add(ctn, pathbar->widget);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = pathbar;
@@ -976,10 +1003,10 @@
}
}
- if(args.onactivate) {
+ if(args->onactivate) {
UiEventData *eventdata = malloc(sizeof(UiEventData));
- eventdata->callback = args.onactivate;
- eventdata->userdata = args.onactivatedata;
+ eventdata->callback = args->onactivate;
+ eventdata->userdata = args->onactivatedata;
eventdata->obj = obj;
eventdata->value = 0;
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/text.h
--- a/ui/motif/text.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/text.h Sun Jul 20 22:04:39 2025 +0200
@@ -64,6 +64,9 @@
int last_selection_state;
} UiTextArea;
+void ui_textarea_save(UiText *text);
+void ui_textarea_restore(UiText *text);
+void ui_textarea_text_destroy(UiText *text);
char* ui_textarea_get(UiText *text);
void ui_textarea_set(UiText *text, const char *str);
char* ui_textarea_getsubstr(UiText *text, int begin, int end);
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/toolkit.c
--- a/ui/motif/toolkit.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/toolkit.c Sun Jul 20 22:04:39 2025 +0200
@@ -52,17 +52,18 @@
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
static ui_callback appclose_fnc;
static void *appclose_udata;
static int is_toplevel_realized = 0;
-int event_pipe[2];
+static int event_pipe[2];
+static UiBool exit_on_shutdown;
static String fallback[] = {
//"*fontList: -dt-interface system-medium-r-normal-s*utf*:",
@@ -139,6 +140,10 @@
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_main() {
if(startup_func) {
startup_func(NULL, startup_data);
@@ -148,6 +153,9 @@
exit_func(NULL, exit_data);
}
uic_store_app_properties();
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
void ui_exit_mainloop() {
@@ -202,6 +210,7 @@
event.document = job->obj->ctx->document;
event.intval = 0;
event.eventdata = NULL;
+ event.eventdatatype = 0;
job->finish_callback(&event, job->finish_data);
}
free(job);
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/tree.c
--- a/ui/motif/tree.c Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,328 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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
-#include
-#include
-#include
-
-#include "tree.h"
-
-#include "container.h"
-#include "../common/object.h"
-#include "../common/context.h"
-#include
-#include
-#include
-
-UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) {
- // TODO: check if modelinfo is complete
-
- Arg args[32];
- int n = 0;
-
- // create scrolled window
- UiContainer *ct = uic_get_current_container(obj);
- Widget parent = ct->prepare(ct, args, &n, TRUE);
-
- XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC);
- n++;
- XtSetArg(args[n], XmNshadowThickness, 0);
- n++;
- Widget scrollw = XmCreateScrolledWindow(parent, "scroll_win", args, n);
- ct->add(ct, scrollw);
- XtManageChild(scrollw);
-
- // create table headers
- XmStringTable header = (XmStringTable)XtMalloc(
- model->columns * sizeof(XmString));
- for(int i=0;icolumns;i++) {
- header[i] = XmStringCreateLocalized(model->titles[i]);
- }
- n = 0;
- XtSetArg(args[n], XmNdetailColumnHeading, header);
- n++;
- XtSetArg(args[n], XmNdetailColumnHeadingCount, model->columns);
- n++;
-
- // set res
- XtSetArg(args[n], XmNlayoutType, XmDETAIL);
- n++;
- XtSetArg(args[n], XmNentryViewType, XmSMALL_ICON);
- n++;
- XtSetArg(args[n], XmNselectionPolicy, XmSINGLE_SELECT);
- n++;
- XtSetArg(args[n], XmNwidth, 600);
- n++;
-
- // create widget
- //UiContainer *ct = uic_get_current_container(obj);
- //Widget parent = ct->add(ct, args, &n);
-
- Widget container = XmCreateContainer(scrollw, "table", args, n);
- XtManageChild(container);
-
- // add callbacks
- UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
- event->obj = obj;
- event->activate = cb.activate;
- event->selection = cb.selection;
- event->userdata = cb.userdata;
- event->last_selection = NULL;
- if(cb.selection) {
- XtAddCallback(
- container,
- XmNselectionCallback,
- (XtCallbackProc)ui_table_select_callback,
- event);
- }
- if(cb.activate) {
- XtAddCallback(
- container,
- XmNdefaultActionCallback,
- (XtCallbackProc)ui_table_action_callback,
- event);
- }
-
- // add initial data
- UiList *list = var->value;
- void *data = list->first(list);
- int width = 0;
- while(data) {
- int w = ui_add_icon_gadget(container, model, data);
- if(w > width) {
- width = w;
- }
- data = list->next(list);
- }
-
- UiTableView *tableview = cxMalloc(obj->ctx->allocator, sizeof(UiTableView));
- tableview->widget = container;
- tableview->var = var;
- tableview->model = model;
-
- // set new XmContainer width
- XtVaSetValues(container, XmNwidth, width, NULL);
-
- // cleanup
- for(int i=0;icolumns;i++) {
- XmStringFree(header[i]);
- }
- XtFree((char*)header);
-
- return scrollw;
-}
-
-UIWIDGET ui_table(UiObject *obj, UiList *data, UiModel *model, UiListCallbacks cb) {
- UiVar *var = malloc(sizeof(UiVar));
- var->value = data;
- var->type = UI_VAR_SPECIAL;
- return ui_table_var(obj, var, model, cb);
-}
-
-void ui_table_update(UiEvent *event, UiTableView *view) {
- // clear container
- Widget *children;
- int nc;
-
- XtVaGetValues(
- view->widget,
- XmNchildren,
- &children,
- XmNnumChildren,
- &nc,
- NULL);
-
- for(int i=0;ivar->value;
-
- void *data = list->first(list);
- int width = 0;
- while(data) {
- int w = ui_add_icon_gadget(view->widget, view->model, data);
- if(w > width) {
- width = w;
- }
- data = list->next(list);
- }
-
-}
-
-#define UI_COL_CHAR_WIDTH 12
-
-int ui_add_icon_gadget(Widget container, UiModel *model, void *data) {
- int width = 50;
-
- if(model->columns == 0) {
- return width;
- }
-
- XmString label = NULL;
- Arg args[8];
- Boolean f;
- // first column
- if(model->types[0] != 12345678) { // TODO: icon/label type
- char *str = ui_type_to_string(
- model->types[0],
- model->getvalue(data, 0),
- &f);
-
- // column width
- width += strlen(str) * UI_COL_CHAR_WIDTH;
-
-
- XmString label = XmStringCreateLocalized(str);
- XtSetArg(args[0], XmNlabelString, label);
- if(f) {
- free(str);
- }
- } else {
- // TODO
- }
-
- // remaining columns are the icon gadget details
- XmStringTable details = (XmStringTable)XtMalloc(
- (model->columns - 1) * sizeof(XmString));
- for(int i=1;icolumns;i++) {
- char *str = ui_type_to_string(
- model->types[i],
- model->getvalue(data, i),
- &f);
-
- // column width
- width += strlen(str) * UI_COL_CHAR_WIDTH;
-
- details[i - 1] = XmStringCreateLocalized(str);
- if(f) {
- free(str);
- }
- }
- XtSetArg(args[1], XmNdetail, details);
- XtSetArg(args[2], XmNdetailCount, model->columns - 1);
- XtSetArg(args[3], XmNshadowThickness, 0);
- // create widget
- Widget item = XmCreateIconGadget(container, "table_item", args, 4);
- XtManageChild(item);
-
- // cleanup
- XmStringFree(label);
- for(int i=0;icolumns-1;i++) {
- XmStringFree(details[i]);
- }
- XtFree((char*)details);
-
- return width;
-}
-
-char* ui_type_to_string(UiModelType type, void *data, Boolean *free) {
- switch(type) {
- case UI_STRING: *free = FALSE; return data;
- case UI_INTEGER: {
- *free = TRUE;
- int *val = data;
- cxmutstr str = cx_asprintf("%d", *val);
- return str.ptr;
- }
- case UI_ICON: break; // TODO
- case UI_ICON_TEXT: break; // TODO
- }
- *free = FALSE;
- return NULL;
-}
-
-void ui_table_action_callback(
- Widget widget,
- UiTreeEventData *event,
- XmContainerSelectCallbackStruct *sel)
-{
- UiListSelection *selection = ui_list_selection(sel);
-
- UiEvent e;
- e.obj = event->obj;
- e.window = event->obj->window;
- e.document = event->obj->ctx->document;
- e.eventdata = selection;
- e.intval = selection->count > 0 ? selection->rows[0] : -1;
- event->activate(&e, event->userdata);
-
- free(event->last_selection->rows);
- free(event->last_selection);
- event->last_selection = selection;
-}
-
-void ui_table_select_callback(
- Widget widget,
- UiTreeEventData *event,
- XmContainerSelectCallbackStruct *sel)
-{
- UiListSelection *selection = ui_list_selection(sel);
- if(!ui_compare_list_selection(selection, event->last_selection)) {
- UiEvent e;
- e.obj = event->obj;
- e.window = event->obj->window;
- e.document = event->obj->ctx->document;
- e.eventdata = selection;
- e.intval = selection->count > 0 ? selection->rows[0] : -1;
- event->selection(&e, event->userdata);
- }
- if(event->last_selection) {
- free(event->last_selection->rows);
- free(event->last_selection);
- }
- event->last_selection = selection;
-}
-
-UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs) {
- UiListSelection *selection = malloc(sizeof(UiListSelection));
- selection->count = xs->selected_item_count;
- selection->rows = calloc(selection->count, sizeof(int));
- for(int i=0;icount;i++) {
- int index;
- XtVaGetValues(xs->selected_items[i], XmNpositionIndex, &index, NULL);
- selection->rows[i] = index;
- }
- return selection;
-}
-
-Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2) {
- if(!s1 || !s2) {
- return FALSE;
- }
- if(s1->count != s2->count) {
- return FALSE;
- }
- for(int i=0;icount;i++) {
- if(s1->rows[i] != s2->rows[i]) {
- return FALSE;
- }
- }
- return TRUE;
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/tree.h
--- a/ui/motif/tree.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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 TREE_H
-#define TREE_H
-
-#include "../ui/tree.h"
-#include "../common/context.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct UiTreeEventData {
- UiObject *obj;
- ui_callback activate;
- ui_callback selection;
- void *userdata;
- UiListSelection *last_selection;
-} UiTreeEventData;
-
-typedef struct UiTableView {
- Widget widget;
- UiVar *var;
- UiModel *model;
-} UiTableView;
-
-void ui_table_update(UiEvent *event, UiTableView *view);
-int ui_add_icon_gadget(Widget container, UiModel *model, void *data);
-char* ui_type_to_string(UiModelType type, void *data, Boolean *free);
-
-void ui_table_action_callback(
- Widget widget,
- UiTreeEventData *event,
- XmContainerSelectCallbackStruct *sel);
-void ui_table_select_callback(
- Widget widget,
- UiTreeEventData *event,
- XmContainerSelectCallbackStruct *sel);
-
-UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs);
-
-Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TREE_H */
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/widget.c
--- a/ui/motif/widget.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/widget.c Sun Jul 20 22:04:39 2025 +0200
@@ -37,7 +37,7 @@
#include "../common/object.h"
-UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
Arg xargs[64];
int n = 0;
@@ -56,12 +56,11 @@
UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) {
Arg xargs[64];
int n = 0;
- UiWidgetArgs a = *args;
UiContainerPrivate *ctn = ui_obj_container(obj);
- UI_APPLY_LAYOUT(ctn->layout, a);
+ UI_APPLY_LAYOUT(ctn->layout, args);
- char *name = a.name ? (char*)a.name : "separator";
+ char *name = args->name ? (char*)args->name : "separator";
Widget parent = ctn->prepare(ctn, xargs, &n);
Widget widget = XmCreateSeparator(parent, name, xargs, n);
XtManageChild(widget);
@@ -69,3 +68,11 @@
return widget;
}
+
+void ui_widget_set_size(UIWIDGET w, int width, int height) {
+
+}
+
+void ui_widget_redraw(UIWIDGET w) {
+
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/motif/window.c
--- a/ui/motif/window.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/motif/window.c Sun Jul 20 22:04:39 2025 +0200
@@ -70,8 +70,7 @@
static UiObject* create_window(const char *title, void *window_data, Boolean simple) {
CxMempool *mp = cxMempoolCreateSimple(256);
const CxAllocator *a = mp->allocator;
- UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
- obj->ctx = uic_context(obj, mp);
+ UiObject *obj = uic_object_new_toplevel();
obj->window = window_data;
obj->destroy = ui_window_widget_destroy;
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/Makefile
--- a/ui/qt/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -37,5 +37,9 @@
$(MAKE) -f $(QT_MAKEFILE)
$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
+$(UI_SHLIB): $(OBJ)
+ $(MAKE) -f $(QT_MAKEFILE)
+ $(CXX) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
+
FORCE:
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/button.cpp
--- a/ui/qt/button.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/button.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 2015 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -30,20 +30,20 @@
#include "container.h"
#include "toolkit.h"
-UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) {
+UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- QString str = QString::fromUtf8(args.label);
+ QString str = QString::fromUtf8(args->label);
QPushButton *button = new QPushButton(str);
- if(args.onclick) {
- UiEventWrapper *event = new UiEventWrapper(obj, args.onclick, args.onclickdata);
+ if(args->onclick) {
+ UiEventWrapper *event = new UiEventWrapper(obj, args->onclick, args->onclickdata);
button->connect(button, SIGNAL(clicked()), event, SLOT(slot()));
button->connect(button, SIGNAL(destroyed()), event, SLOT(destroy()));
}
- ctn->add(button, false);
+ ctn->add(button);
return button;
}
@@ -53,21 +53,22 @@
event->intval = button->isChecked();
if(wrapper->var) {
event->eventdata = wrapper->var->value;
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
}
}
-UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- QString str = QString::fromUtf8(args.label);
+ QString str = QString::fromUtf8(args->label);
QPushButton *button = new QPushButton(str);
button->setCheckable(true);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
- if(args.onchange) {
- UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata);
+ if(args->onchange) {
+ UiEventWrapper *event = new UiEventWrapper(obj, args->onchange, args->onchangedata);
event->var = var;
event->customdata1 = button;
event->prepare_event = togglebutton_event;
@@ -87,7 +88,7 @@
i->set = ui_togglebutton_set;
}
- ctn->add(button, false);
+ ctn->add(button);
return button;
}
@@ -111,21 +112,22 @@
event->intval = button->isChecked();
if(wrapper->var) {
event->eventdata = wrapper->var->value;
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
}
}
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- QString str = QString::fromUtf8(args.label);
+ QString str = QString::fromUtf8(args->label);
QCheckBox *checkbox = new QCheckBox(str);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
- if(args.onchange) {
- UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata);
+ if(args->onchange) {
+ UiEventWrapper *event = new UiEventWrapper(obj, args->onchange, args->onchangedata);
event->var = var;
event->customdata1 = checkbox;
event->prepare_event = checkbox_event;
@@ -145,7 +147,7 @@
i->set = ui_checkbox_set;
}
- ctn->add(checkbox, false);
+ ctn->add(checkbox);
return checkbox;
}
@@ -167,21 +169,22 @@
static void radiobutton_event(UiEvent *event, UiEventWrapper *wrapper) {
if(wrapper->var) {
- UiInteger *value = wrapper->var->value;
+ UiInteger *value = (UiInteger*)wrapper->var->value;
event->eventdata = value;
- event->intval = ui_get(value);
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
+ event->intval = value->get(value);
}
}
-UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
+UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- QString str = QString::fromUtf8(args.label);
+ QString str = QString::fromUtf8(args->label);
QRadioButton *button = new QRadioButton(str);
button->setAutoExclusive(false);
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
UiInteger *value = (UiInteger*)var->value;
QButtonGroup *buttonGroup = (QButtonGroup*)value->obj;
@@ -198,14 +201,14 @@
value->set = ui_radiobutton_set;
}
- UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata);
+ UiEventWrapper *event = new UiEventWrapper(obj, args->onchange, args->onchangedata);
event->var = var;
event->customdata1 = button;
event->prepare_event = togglebutton_event;
button->connect(button, SIGNAL(clicked()), event, SLOT(slot()));
button->connect(button, SIGNAL(destroyed()), event, SLOT(destroy()));
- ctn->add(button, false);
+ ctn->add(button);
return button;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/button.h
--- a/ui/qt/button.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/button.h Sun Jul 20 22:04:39 2025 +0200
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 2015 Olaf Wintermann. All rights reserved.
+ * 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:
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/container.cpp
--- a/ui/qt/container.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/container.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -60,17 +60,14 @@
ui_reset_layout(layout);
}
-void UiBoxContainer::add(QWidget* widget, bool fill) {
- if(layout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(layout.fill);
- }
-
+void UiBoxContainer::add(QWidget* widget) {
+ bool fill = layout.fill;
if(hasStretchedWidget && fill) {
fill = false;
fprintf(stderr, "UiError: container has 2 filled widgets");
}
- box->addWidget(widget, fill);
+ box->addWidget(widget);
if(!hasStretchedWidget) {
QSpacerItem *newspace = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
@@ -86,25 +83,25 @@
current = widget;
}
-UIWIDGET ui_box(UiObject *obj, UiContainerArgs args, QBoxLayout::Direction dir) {
+UIWIDGET ui_box(UiObject *obj, UiContainerArgs *args, QBoxLayout::Direction dir) {
UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
QWidget *widget = new QWidget();
QBoxLayout *box = new QBoxLayout(dir);
widget->setLayout(box);
- ctn->add(widget, true);
+ ctn->add(widget);
ui_container_add(obj, new UiBoxContainer(box));
return widget;
}
-UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box(obj, args, QBoxLayout::TopToBottom);
}
-UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
return ui_box(obj, args, QBoxLayout::LeftToRight);
}
@@ -133,16 +130,17 @@
ui_reset_layout(layout);
}
-void UiGridContainer::add(QWidget* widget, bool fill) {
+void UiGridContainer::add(QWidget* widget) {
if(layout.newline) {
x = 0;
y++;
}
- int hexpand = false;
- int vexpand = false;
- int hfill = false;
- int vfill = false;
+ bool fill = layout.fill;
+ bool hexpand = false;
+ bool vexpand = false;
+ bool hfill = false;
+ bool vfill = false;
if(!layout.override_defaults) {
if(def_hexpand) {
hexpand = true;
@@ -158,9 +156,6 @@
}
}
- if(layout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(layout.fill);
- }
if(layout.hexpand) {
hexpand = true;
//hfill = true;
@@ -233,24 +228,24 @@
}
}
-UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
QWidget *widget = new QWidget();
QGridLayout *grid = new QGridLayout();
widget->setLayout(grid);
- ctn->add(widget, true);
+ ctn->add(widget);
ui_container_add(obj, new UiGridContainer(
grid,
- args.margin,
- args.columnspacing,
- args.rowspacing,
- args.def_hexpand,
- args.def_vexpand,
- args.def_hfill,
- args.def_vfill));
+ args->margin,
+ args->columnspacing,
+ args->rowspacing,
+ args->def_hexpand,
+ args->def_vexpand,
+ args->def_hfill,
+ args->def_vfill));
return widget;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/container.h
--- a/ui/qt/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -41,14 +41,14 @@
#include
#define UI_APPLY_LAYOUT(layout, args) \
- layout.fill = args.fill; \
- layout.hexpand = args.hexpand; \
- layout.vexpand = args.vexpand; \
- layout.hfill = args.hfill; \
- layout.vfill = args.vfill; \
- layout.override_defaults = args.override_defaults; \
- layout.colspan = args.colspan; \
- layout.rowspan = args.rowspan
+ layout.fill = args->fill; \
+ layout.hexpand = args->hexpand; \
+ layout.vexpand = args->vexpand; \
+ layout.hfill = args->hfill; \
+ layout.vfill = args->vfill; \
+ layout.override_defaults = args->override_defaults; \
+ layout.colspan = args->colspan; \
+ layout.rowspan = args->rowspan
#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE)
@@ -64,7 +64,7 @@
typedef struct UiLayout UiLayout;
struct UiLayout {
- UiTri fill;
+ UiBool fill;
UiBool newline;
char *label;
UiBool hexpand;
@@ -81,7 +81,7 @@
UiLayout layout;
UIWIDGET current;
- virtual void add(QWidget *widget, bool fill) = 0;
+ virtual void add(QWidget *widget) = 0;
virtual void end() {}
};
@@ -93,7 +93,7 @@
UiBoxContainer(QBoxLayout *box);
- virtual void add(QWidget *widget, bool fill);
+ virtual void add(QWidget *widget);
};
class UiGridContainer : public UiContainerPrivate {
@@ -120,7 +120,7 @@
bool def_hfill,
bool def_vfill);
- virtual void add(QWidget *widget, bool fill);
+ virtual void add(QWidget *widget);
virtual void end();
};
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/entry.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/entry.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,180 @@
+/*
+ * 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 "entry.h"
+
+#include "container.h"
+#include "../common/context.h"
+
+#include
+#include
+
+
+
+UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UI_APPLY_LAYOUT(ctn->layout, args);
+
+ bool use_double = false;
+ UiVar *var = NULL;
+ if(args->varname) {
+ var = uic_get_var(obj->ctx, args->varname);
+ if(var->type == UI_VAR_DOUBLE) {
+ use_double = true;
+ } else if(var->type == UI_VAR_RANGE) {
+ use_double = true;
+ } else if(var->type != UI_VAR_INTEGER) {
+ var = NULL;
+ fprintf(stderr, "UI Error: var '%s' has wrong type (must be int/double/range)\n", args->varname);
+ }
+ }
+
+ if(!var) {
+ if(args->intvalue) {
+ var = uic_widget_var(obj->ctx, obj->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
+ } else if(args->doublevalue) {
+ var = uic_widget_var(obj->ctx, obj->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
+ use_double = true;
+ } else if(args->rangevalue) {
+ var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
+ use_double = true;
+ } else {
+ if(args->digits > 0) {
+ use_double = true;
+ }
+ }
+ }
+
+ QAbstractSpinBox *widget = nullptr;
+ if(use_double) {
+ QDoubleSpinBox *spinbox = new QDoubleSpinBox();
+ spinbox->setDecimals(args->digits);
+ if(args->step != 0) {
+ spinbox->setSingleStep(args->step);
+ }
+ widget = spinbox;
+ } else {
+ QSpinBox *spinbox = new QSpinBox();
+ if(args->step != 0) {
+ spinbox->setSingleStep(args->step);
+ }
+ widget = spinbox;
+ }
+
+ if(var) {
+ if(var->type == UI_VAR_INTEGER) {
+ UiInteger *value = (UiInteger*)var->value;
+ value->obj = widget;
+ if(value->value != 0) {
+ QSpinBox *spinbox = (QSpinBox*)widget;
+ spinbox->setValue(value->value);
+ }
+ value->get = ui_spinbox_int_get;
+ value->set = ui_spinbox_int_set;
+ } else if(var->type == UI_VAR_DOUBLE) {
+ UiDouble *value = (UiDouble*)var->value;
+ value->obj = widget;
+ if(value->value != 0) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)widget;
+ spinbox->setValue(value->value);
+ }
+ value->get = ui_spinbox_double_get;
+ value->set = ui_spinbox_double_set;
+ } else if(var->type == UI_VAR_RANGE) {
+ UiRange *value = (UiRange*)var->value;
+ value->obj = widget;
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)widget;
+ if(value->value != 0) {
+ spinbox->setValue(value->value);
+ }
+ if(value->min != value->max) {
+ spinbox->setRange(value->min, value->max);
+ }
+ if(value->extent != 0) {
+ spinbox->setSingleStep(value->extent);
+ }
+ value->get = ui_spinbox_range_get;
+ value->set = ui_spinbox_range_set;
+ value->setrange = ui_spinbox_range_setrange;
+ value->setextent = ui_spinbox_range_setextent;
+ }
+ }
+
+
+ ctn->add(widget);
+ return widget;
+}
+
+int64_t ui_spinbox_int_get(UiInteger *i) {
+ QSpinBox *spinbox = (QSpinBox*)i->obj;
+ i->value = spinbox->value();
+ return i->value;
+}
+
+void ui_spinbox_int_set(UiInteger *i, int64_t value) {
+ QSpinBox *spinbox = (QSpinBox*)i->obj;
+ spinbox->setValue(value);
+ i->value = spinbox->value();
+}
+
+double ui_spinbox_double_get(UiDouble *d) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)d->obj;
+ d->value = spinbox->value();
+ return d->value;
+}
+
+void ui_spinbox_double_set(UiDouble *d, double value) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)d->obj;
+ spinbox->setValue(value);
+ d->value = spinbox->value();
+}
+
+double ui_spinbox_range_get(UiRange *range) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)range->obj;
+ range->value = spinbox->value();
+ return range->value;
+}
+
+void ui_spinbox_range_set(UiRange *range, double value) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)range->obj;
+ spinbox->setValue(value);
+ range->value = spinbox->value();
+}
+
+void ui_spinbox_range_setrange(UiRange *range, double min, double max) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)range->obj;
+ spinbox->setRange(min, max);
+ range->min = min;
+ range->max = max;
+}
+
+void ui_spinbox_range_setextent(UiRange *range, double extent) {
+ QDoubleSpinBox *spinbox = (QDoubleSpinBox*)range->obj;
+ spinbox->setSingleStep(extent);
+ range->extent = extent;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/entry.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/entry.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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 ENTRY_H
+#define ENTRY_H
+
+#include "../ui/entry.h"
+#include "toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int64_t ui_spinbox_int_get(UiInteger *i);
+void ui_spinbox_int_set(UiInteger *i, int64_t value);
+
+double ui_spinbox_double_get(UiDouble *d);
+void ui_spinbox_double_set(UiDouble *d, double value);
+
+double ui_spinbox_range_get(UiRange *range);
+void ui_spinbox_range_set(UiRange *range, double value);
+void ui_spinbox_range_setrange(UiRange *range, double min, double max);
+void ui_spinbox_range_setextent(UiRange *range, double extent);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ENTRY_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/image.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/image.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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 "image.h"
+
+
+
+void ui_image_ref(UIIMAGE img) {
+ // TODO
+}
+
+void ui_image_unref(UIIMAGE img) {
+ // TODO
+}
\ No newline at end of file
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/image.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/image.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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 IMAGE_H
+#define IMAGE_H
+
+#include "toolkit.h"
+#include "../ui/image.h"
+
+#endif /* IMAGE_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/label.cpp
--- a/ui/qt/label.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/label.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -32,32 +32,32 @@
#include "ui/display.h"
-UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs args) {
+UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- QString str = QString::fromUtf8(args.label);
+ QString str = QString::fromUtf8(args->label);
QLabel *widget = new QLabel(str);
Qt::AlignmentFlag align = Qt::AlignCenter;
- if(args.align == UI_ALIGN_LEFT) {
+ if(args->align == UI_ALIGN_LEFT) {
align = Qt::AlignLeft;
- } else if(args.align == UI_ALIGN_RIGHT) {
+ } else if(args->align == UI_ALIGN_RIGHT) {
align = Qt::AlignRight;
}
widget->setAlignment(align);
- ctn->add(widget, false);
+ ctn->add(widget);
return widget;
}
-UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) {
- args.align = UI_ALIGN_LEFT;
+UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_LEFT;
return ui_label_create(obj, args);
}
-UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args) {
- args.align = UI_ALIGN_RIGHT;
+UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_RIGHT;
return ui_label_create(obj, args);
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/list.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/list.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,130 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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 "list.h"
+#include "container.h"
+
+#include
+#include
+#include
+
+extern "C" void* ui_strmodel_getvalue(void *elm, int column) {
+ return column == 0 ? elm : NULL;
+}
+
+static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
+ return getvalue(elm, col);
+}
+
+UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args) {
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UI_APPLY_LAYOUT(ctn->layout, args);
+
+ QListView *view = new QListView();
+ ui_getvaluefunc2 getvalue = nullptr;
+ void *getvaluedata = nullptr;
+ if(args->getvalue2) {
+ getvalue = args->getvalue2;
+ getvaluedata = args->getvalue2data;
+ } else if(args->getvalue) {
+ getvalue = getvalue_wrapper;
+ getvaluedata = (void*)args->getvalue;
+ } else {
+ getvalue = getvalue_wrapper;
+ getvaluedata = (void*)ui_strmodel_getvalue;
+ }
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+
+ ListModel *model = new ListModel(obj, view, var, getvalue, getvaluedata);
+ view->setModel(model);
+
+ if(var) {
+ UiList *list = (UiList*)var->value;
+ list->update = ui_listmodel_update;
+ list->getselection = ui_listmodel_getselection;
+ list->setselection = ui_listmodel_setselection;
+ list->obj = model;
+ }
+
+ model->setActivationCallback(args->onactivate, args->onactivatedata);
+ model->setSelectionCallback(args->onselection, args->onselectiondata);
+
+ QItemSelectionModel *s = view->selectionModel();
+ QObject::connect(
+ s,
+ SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ model,
+ SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));
+
+
+ ctn->add(view);
+
+ return view;
+}
+
+UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args) {
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UI_APPLY_LAYOUT(ctn->layout, args);
+
+ QTreeView *view = new QTreeView();
+ view->setItemsExpandable(false);
+ view->setRootIsDecorated(false);
+ if(args->multiselection) {
+ view->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ }
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+
+ TableModel *model = new TableModel(obj, view, var, args->model);
+ view->setModel(model);
+
+ if(var) {
+ UiList *list = (UiList*)var->value;
+ list->update = ui_listmodel_update;
+ list->getselection = ui_listmodel_getselection;
+ list->setselection = ui_listmodel_setselection;
+ list->obj = model;
+ }
+
+ model->setActivationCallback(args->onactivate, args->onactivatedata);
+ model->setSelectionCallback(args->onselection, args->onselectiondata);
+
+ QItemSelectionModel *s = view->selectionModel();
+ QObject::connect(
+ s,
+ SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ model,
+ SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));
+
+
+ ctn->add(view);
+
+ return view;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/list.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/qt/list.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,40 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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 TREE_H
+#define TREE_H
+
+#include "../ui/tree.h"
+#include "model.h"
+
+#include
+
+
+
+#endif /* TREE_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/menu.cpp
--- a/ui/qt/menu.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/menu.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -157,6 +157,7 @@
if(action->var) {
UiInteger *value = (UiInteger*)action->var->value;
event->eventdata = value;
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
event->intval = value->get(value);
}
}
@@ -217,6 +218,7 @@
void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action) {
if(action->var) {
event->eventdata = action->var->value;
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
}
event->intval = action->isChecked();
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/model.cpp
--- a/ui/qt/model.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/model.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -28,3 +28,245 @@
#include "model.h"
+static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
+ if(model->getvalue2) {
+ return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
+ } else if(model->getvalue) {
+ return model->getvalue(elm, col);
+ }
+ return NULL;
+}
+
+ListModel::ListModel(UiObject *obj, QListView *view, UiVar *var, ui_getvaluefunc2 getvalue, void *getvaluedata){
+ this->obj = obj;
+ this->view = view;
+ this->var = var;
+ this->getvalue = getvalue;
+ this->getvaluedata = getvaluedata;
+ this->onactivate = nullptr;
+ this->onactivatedata = nullptr;
+ this->onselection = nullptr;
+ this->onselectiondata = nullptr;
+}
+
+void ListModel::setActivationCallback(ui_callback f, void *userdata) {
+ onactivate = f;
+ onactivatedata = userdata;
+}
+
+void ListModel::setSelectionCallback(ui_callback f, void *userdata) {
+ onselection = f;
+ onselectiondata = userdata;
+}
+
+void ListModel::update(int row) {
+ if(row >= 0) {
+ this->update(row);
+ } else {
+ this->beginResetModel();
+ this->endResetModel();
+ }
+}
+
+int ListModel::rowCount(const QModelIndex& parent) const {
+ UiList *list = (UiList*)var->value;
+ return ui_list_count(list);
+}
+
+QVariant ListModel::data(const QModelIndex &index, int role) const {
+ if(role == Qt::DisplayRole) {
+ UiList *ls = (UiList*)var->value;
+ void *rowData = ls->get(ls, index.row());
+ if(rowData && getvalue) {
+ UiBool freeResult = false;
+ void *value = getvalue(ls, rowData, index.row(), 0, getvaluedata, &freeResult);
+ if(value) {
+ auto qs = QString::fromUtf8((char*)value);
+ if(freeResult) {
+ free(value);
+ }
+ return qs;
+ }
+ }
+ }
+ return QVariant();
+}
+
+void ListModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
+ UiListSelection sel = ui_selection_model_to_selection(view->selectionModel());
+
+ UiEvent event;
+ event.obj = obj;
+ event.window = obj->window;
+ event.document = obj->ctx->document;
+ event.eventdata = &sel;
+ event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
+ event.intval = sel.count;
+ event.set = ui_get_setop();
+
+ if(onactivate) {
+ onactivate(&event, onactivatedata);
+ }
+ if(onselection) {
+ onselection(&event, onselectiondata);
+ }
+
+ free(sel.rows);
+}
+
+
+
+TableModel::TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model){
+ this->obj = obj;
+ this->view = view;
+ this->var = var;
+ this->model = model;
+ this->onactivate = nullptr;
+ this->onactivatedata = nullptr;
+ this->onselection = nullptr;
+ this->onselectiondata = nullptr;
+}
+
+void TableModel::setActivationCallback(ui_callback f, void *userdata) {
+ onactivate = f;
+ onactivatedata = userdata;
+}
+
+void TableModel::setSelectionCallback(ui_callback f, void *userdata) {
+ onselection = f;
+ onselectiondata = userdata;
+}
+
+void TableModel::update(int row) {
+ if(row >= 0) {
+ this->update(row);
+ } else {
+ this->beginResetModel();
+ this->endResetModel();
+ }
+}
+
+int TableModel::rowCount(const QModelIndex& parent) const {
+ UiList *list = (UiList*)var->value;
+ return ui_list_count(list);
+}
+
+int TableModel::columnCount(const QModelIndex &parent) const {
+ return model->columns;
+}
+
+QVariant TableModel::data(const QModelIndex &index, int role) const {
+ if(role == Qt::DisplayRole) {
+ UiList *ls = (UiList*)var->value;
+ void *rowData = ls->get(ls, index.row());
+ if(rowData) {
+ int col = index.column();
+ UiBool freeResult = false;
+ void *value = model_getvalue(model, ls, rowData, index.row(), col, &freeResult);
+ if(value) {
+ UiModelType type = model->types[col];
+ switch(type) {
+ case UI_STRING: {
+ auto qs = QString::fromUtf8((char*)value);
+ if(freeResult) {
+ free(value);
+ }
+ return qs;
+ }
+ case UI_STRING_FREE: {
+ QString s = QString::fromUtf8((char*)value);
+ free(value);
+ return s;
+ }
+ case UI_INTEGER: {
+ intptr_t i = (intptr_t)value;
+ return QString::number(i);
+ }
+ case UI_ICON: {
+ break; // TODO
+ }
+ case UI_ICON_TEXT: {
+ break; // TODO
+ }
+ case UI_ICON_TEXT_FREE: {
+ break; // TODO
+ }
+ }
+ }
+ }
+ }
+ return QVariant();
+}
+
+QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const {
+ if(role == Qt::DisplayRole) {
+ char *label = model->titles[section];
+ return QString::fromUtf8(label);
+ }
+ return QVariant();
+}
+
+void TableModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
+ UiListSelection sel = ui_selection_model_to_selection(view->selectionModel());
+
+ UiEvent event;
+ event.obj = obj;
+ event.window = obj->window;
+ event.document = obj->ctx->document;
+ event.eventdata = &sel;
+ event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
+ event.intval = sel.count;
+ event.set = ui_get_setop();
+
+ if(onactivate) {
+ onactivate(&event, onactivatedata);
+ }
+ if(onselection) {
+ onselection(&event, onselectiondata);
+ }
+
+ free(sel.rows);
+}
+
+
+
+UiListSelection ui_selection_model_to_selection(QItemSelectionModel *model) {
+ UiListSelection sel;
+ sel.rows = NULL;
+ sel.count = 0;
+
+ if(model->hasSelection()) {
+ QModelIndexList indices = model->selectedIndexes();
+ sel.count = indices.count();
+ sel.rows = (int*)calloc(sel.count, sizeof(int));
+
+ int i = 0;
+ for (const QModelIndex &index : indices) {
+ sel.rows[i++] = index.row();
+ }
+ }
+
+ return sel;
+}
+
+/* ---------------------- UiList implementation -----------------------------*/
+
+void ui_listmodel_update(UiList *list, int row) {
+ ListModel *model = (ListModel*)list->obj;
+ model->update(row);
+}
+
+void ui_listmodel_setselection(UiList *list, UiListSelection sel) {
+ ListModel *model = (ListModel*)list->obj;
+ QItemSelection selection;
+ for (int i=0;iindex(sel.rows[i]);
+ selection.select(index, index);
+ }
+ model->view->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
+}
+
+UiListSelection ui_listmodel_getselection(UiList *list) {
+ ListModel *model = (ListModel*)list->obj;
+ return ui_selection_model_to_selection(model->view->selectionModel());
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/model.h
--- a/ui/qt/model.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/model.h Sun Jul 20 22:04:39 2025 +0200
@@ -40,5 +40,80 @@
#include
+
+class ListModel : public QAbstractListModel {
+ Q_OBJECT
+
+ ui_getvaluefunc2 getvalue;
+ void *getvaluedata;
+ ui_callback onactivate;
+ void *onactivatedata;
+ ui_callback onselection;
+ void *onselectiondata;
+
+public:
+ UiObject *obj;
+ UiVar *var;
+ QListView *view;
+
+ ListModel(UiObject *obj, QListView *view, UiVar *var, ui_getvaluefunc2 getvalue, void *getvaluedata);
+
+ void setActivationCallback(ui_callback f, void *userdata);
+ void setSelectionCallback(ui_callback f, void *userdata);
+
+ void update(int row);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+public slots:
+ void selectionChanged(
+ const QItemSelection & selected,
+ const QItemSelection & deselected);
+};
+
+class TableModel : public QAbstractListModel {
+ Q_OBJECT
+
+ UiModel *model;
+ ui_callback onactivate;
+ void *onactivatedata;
+ ui_callback onselection;
+ void *onselectiondata;
+
+public:
+ UiObject *obj;
+ UiVar *var;
+ QTreeView *view;
+
+ TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model);
+
+ void setActivationCallback(ui_callback f, void *userdata);
+ void setSelectionCallback(ui_callback f, void *userdata);
+
+ void update(int row);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+public slots:
+ void selectionChanged(
+ const QItemSelection & selected,
+ const QItemSelection & deselected);
+};
+
+
+UiListSelection ui_selection_model_to_selection(QItemSelectionModel *model);
+
+extern "C" {
+
+ void ui_listmodel_update(UiList *list, int row);
+ void ui_listmodel_setselection(UiList *list, UiListSelection sel);
+ UiListSelection ui_listmodel_getselection(UiList *list);
+
+}
+
#endif /* MODEL_H */
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/qt4.pro
--- a/ui/qt/qt4.pro Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-#
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-#
-# Copyright 2014 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.
-#
-
-TARGET = uitk
-TEMPLATE = lib
-CONFIG += staticlib warn_off debug
-DESTDIR = ../build/lib
-MOC_DIR = ../build/ui/qt
-OBJECTS_DIR = ../build/ui/qt
-
-DEFINES += UI_QT4
-
-SOURCES += toolkit.cpp
-SOURCES += window.cpp
-SOURCES += menu.cpp
-SOURCES += toolbar.cpp
-SOURCES += stock.cpp
-SOURCES += container.cpp
-SOURCES += text.cpp
-SOURCES += model.cpp
-SOURCES += tree.cpp
-SOURCES += button.cpp
-SOURCES += label.cpp
-SOURCES += graphics.cpp
-
-HEADERS += toolkit.h
-HEADERS += window.h
-HEADERS += menu.h
-HEADERS += toolbar.h
-HEADERS += stock.h
-HEADERS += container.h
-HEADERS += text.h
-HEADERS += model.h
-HEADERS += tree.h
-HEADERS += button.h
-HEADERS += label.h
-HEADERS += graphics.h
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/qt5.pro
--- a/ui/qt/qt5.pro Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/qt5.pro Sun Jul 20 22:04:39 2025 +0200
@@ -33,6 +33,8 @@
MOC_DIR = ../build/ui/qt
OBJECTS_DIR = ../build/ui/qt
+QMAKE_CXXFLAGS += -I../ucx
+
QT += core gui widgets
DEFINES += UI_QT5
@@ -45,11 +47,13 @@
SOURCES += container.cpp
SOURCES += text.cpp
SOURCES += model.cpp
-SOURCES += tree.cpp
+SOURCES += list.cpp
SOURCES += button.cpp
SOURCES += label.cpp
SOURCES += graphics.cpp
SOURCES += widget.cpp
+SOURCES += entry.cpp
+SOURCES += image.cpp
HEADERS += toolkit.h
HEADERS += window.h
@@ -59,9 +63,11 @@
HEADERS += container.h
HEADERS += text.h
HEADERS += model.h
-HEADERS += tree.h
+HEADERS += list.h
HEADERS += button.h
HEADERS += label.h
HEADERS += graphics.h
HEADERS += widget.h
+HEADERS += entry.h
+HEADERS += image.h
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/text.cpp
--- a/ui/qt/text.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/text.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -57,16 +57,16 @@
return document;
}
-UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
+UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
QTextEdit *textarea = new QTextEdit();
- ctn->add(textarea, true);
+ ctn->add(textarea);
QTextDocument *document = nullptr;
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
UiText *value = (UiText*)var->value;
@@ -201,23 +201,27 @@
}
void ui_textarea_remove(UiText *text, int begin, int end) {
- // TODO
+ QTextDocument *doc = (QTextDocument*)text->data1;
+ QTextCursor cursor(doc);
+ cursor.setPosition(begin);
+ cursor.setPosition(end, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
}
/* ------------------------------ TextField ------------------------------ */
-static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs args, bool password, bool frameless) {
+static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, bool password, bool frameless) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
QLineEdit *textfield = new QLineEdit();
- ctn->add(textfield, false);
+ ctn->add(textfield);
if(password) {
textfield->setEchoMode(QLineEdit::Password);
}
- UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
UiString *value = (UiString*)var->value;
if(value->value.ptr) {
@@ -237,15 +241,15 @@
return textfield;
}
-UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) {
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, false, false);
}
-UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, false, true);
}
-UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, true, false);
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/toolbar.cpp
--- a/ui/qt/toolbar.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/toolbar.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -32,3 +32,102 @@
#include "menu.h"
#include "stock.h"
+static void add_items(UiObject *obj, QToolBar *toolbar, CxList *defaults, CxMap *items);
+static void create_item(UiObject *obj, QToolBar *toolbar, UiToolbarItemI *i);
+
+QToolBar* ui_create_toolbar(UiObject *obj) {
+ CxMap *items = uic_get_toolbar_items();
+ CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT);
+ CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER);
+ CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT);
+
+ if(!items || cxMapSize(items) == 0) {
+ return nullptr;
+ }
+
+ QToolBar *toolbar = new QToolBar();
+ add_items(obj, toolbar, left_defaults, items);
+ add_items(obj, toolbar, center_defaults, items);
+ add_items(obj, toolbar, right_defaults, items);
+
+
+ return toolbar;
+}
+
+static void add_items(UiObject *obj, QToolBar *toolbar, CxList *defaults, CxMap *items) {
+ CxIterator i = cxListIterator(defaults);
+ cx_foreach(char *, name, i) {
+ UiToolbarItemI *item = (UiToolbarItemI*)cxMapGet(items, name);
+ if(item) {
+ create_item(obj, toolbar, item);
+ } else {
+ fprintf(stderr, "UI Error: unknown toolbar item '%s'\n", name);
+ }
+ }
+}
+
+static void create_item(UiObject *obj, QToolBar *toolbar, UiToolbarItemI *i) {
+ switch(i->type) {
+ case UI_TOOLBAR_ITEM: {
+ ui_toolbar_add_item(obj, toolbar, (UiToolbarItem*)i);
+ break;
+ }
+ case UI_TOOLBAR_TOGGLEITEM: {
+ ui_toolbar_add_toggleitem(obj, toolbar, (UiToolbarToggleItem*)i);
+ break;
+ }
+ case UI_TOOLBAR_MENU: {
+ ui_toolbar_add_menu(obj, toolbar, (UiToolbarMenuItem*)i);
+ break;
+ }
+ default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type);
+ }
+}
+
+void ui_toolbar_add_item(UiObject *obj, QToolBar *toolbar, UiToolbarItem *item) {
+ QAction *action = new QAction();
+ if(item->args.label) {
+ action->setText(item->args.label);
+ }
+ if(item->args.icon) {
+ action->setIcon(QIcon::fromTheme(item->args.icon));
+ }
+ toolbar->addAction(action);
+
+ UiEventWrapper *event = new UiEventWrapper(obj, item->args.onclick, item->args.onclickdata);
+ action->connect(action, SIGNAL(triggered()), event, SLOT(slot()));
+ action->connect(action, SIGNAL(destroyed()), event, SLOT(destroy()));
+}
+
+static void toolbar_togglebutton_event(UiEvent *event, UiEventWrapper *wrapper) {
+ QAction *action = (QAction*)wrapper->customdata1;
+ event->intval = action->isChecked();
+ if(wrapper->var) {
+ event->eventdata = wrapper->var->value;
+ event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE;
+ }
+}
+
+void ui_toolbar_add_toggleitem(UiObject *obj, QToolBar *toolbar, UiToolbarToggleItem *item) {
+ QAction *action = new QAction();
+ action->setCheckable(true);
+ if(item->args.label) {
+ action->setText(item->args.label);
+ }
+ if(item->args.icon) {
+ action->setIcon(QIcon::fromTheme(item->args.icon));
+ }
+ toolbar->addAction(action);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, nullptr, item->args.varname, UI_VAR_INTEGER);
+ UiEventWrapper *event = new UiEventWrapper(obj, item->args.onchange, item->args.onchangedata);
+ event->var = var;
+ event->customdata1 = action;
+ event->prepare_event = toolbar_togglebutton_event;
+ action->connect(action, SIGNAL(triggered()), event, SLOT(slot()));
+ action->connect(action, SIGNAL(destroyed()), event, SLOT(destroy()));
+}
+
+void ui_toolbar_add_menu(UiObject *obj, QToolBar *toolbar, UiToolbarMenuItem *item) {
+
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/toolbar.h
--- a/ui/qt/toolbar.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/toolbar.h Sun Jul 20 22:04:39 2025 +0200
@@ -31,10 +31,14 @@
#include "toolkit.h"
#include "../ui/toolbar.h"
+#include "../common/toolbar.h"
#include
+QToolBar* ui_create_toolbar(UiObject *obj);
-
+void ui_toolbar_add_item(UiObject *obj, QToolBar *toolbar, UiToolbarItem *item);
+void ui_toolbar_add_toggleitem(UiObject *obj, QToolBar *toolbar, UiToolbarToggleItem *item);
+void ui_toolbar_add_menu(UiObject *obj, QToolBar *toolbar, UiToolbarMenuItem *item);
#endif /* TOOLBAR_H */
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/toolkit.cpp
--- a/ui/qt/toolkit.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/toolkit.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -43,15 +43,17 @@
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
static int is_toplevel_realized = 0;
-int app_argc;
-char **app_argv;
-QApplication *application = NULL;
+static int app_argc;
+static char **app_argv;
+static QApplication *application = NULL;
+
+static UiBool exit_on_shutdown;
void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
@@ -87,6 +89,10 @@
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_main() {
if(startup_func) {
startup_func(NULL, startup_data);
@@ -98,6 +104,10 @@
uic_store_app_properties();
delete application;
+
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
void ui_show(UiObject *obj) {
@@ -137,6 +147,7 @@
e.window = obj->window;
e.document = obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = 0;
e.set = ui_get_setop();
if(prepare_event) {
@@ -174,6 +185,7 @@
e.window = obj->window;
e.document = obj->ctx->document;
e.eventdata = NULL;
+ e.eventdatatype = 0;
e.intval = 0;
e.set = ui_get_setop();
if(prepare_event) {
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/tree.cpp
--- a/ui/qt/tree.cpp Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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 "tree.h"
-#include "container.h"
-
-#include
-#include
-#include
-
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/tree.h
--- a/ui/qt/tree.h Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2014 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 TREE_H
-#define TREE_H
-
-#include "../ui/tree.h"
-#include "model.h"
-
-#include
-
-
-
-#endif /* TREE_H */
-
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/widget.cpp
--- a/ui/qt/widget.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/widget.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -31,11 +31,11 @@
#include "container.h"
#include "../common/context.h"
-UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
UIWIDGET widget = create_widget(obj, args, userdata);
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
- ctn->add(widget, false);
+ ctn->add(widget);
return widget;
}
@@ -45,9 +45,9 @@
separator->setFrameShadow(QFrame::Sunken);
UiContainerPrivate *ctn = ui_obj_container(obj);
- UI_APPLY_LAYOUT(ctn->layout, (*args));
+ UI_APPLY_LAYOUT(ctn->layout, args);
- ctn->add(separator, false);
+ ctn->add(separator);
return separator;
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/qt/window.cpp
--- a/ui/qt/window.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/qt/window.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -28,6 +28,7 @@
#include
#include "../common/context.h"
+#include "../common/object.h"
#include "window.h"
#include "menu.h"
@@ -39,9 +40,7 @@
#include
static UiObject* create_window(const char *title, void *window_data, bool simple) {
- CxMempool *mp = cxMempoolCreateSimple(256);
- UiObject *obj = (UiObject*)cxCalloc(mp->allocator, 1, sizeof(UiObject));
- obj->ctx = uic_context(obj, mp);
+ UiObject *obj = uic_object_new_toplevel();
obj->window = window_data;
obj->next = NULL;
@@ -51,8 +50,10 @@
if(!simple) {
ui_add_menus(obj, window);
- //QToolBar *toolbar = ui_create_toolbar(obj);
- //window->addToolBar(Qt::TopToolBarArea, toolbar);
+ QToolBar *toolbar = ui_create_toolbar(obj);
+ if(toolbar) {
+ window->addToolBar(Qt::TopToolBarArea, toolbar);
+ }
}
QBoxLayout *box = new QVBoxLayout();
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/button.h
--- a/ui/ui/button.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/button.h Sun Jul 20 22:04:39 2025 +0200
@@ -36,7 +36,7 @@
#endif
typedef struct UiButtonArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -58,7 +58,7 @@
} UiButtonArgs;
typedef struct UiToggleArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -82,17 +82,17 @@
const int* groups;
} UiToggleArgs;
-#define ui_button(obj, ...) ui_button_create(obj, (UiButtonArgs){ __VA_ARGS__ } )
-#define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_checkbox(obj, ...) ui_checkbox_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_switch(obj, ...) ui_switch_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
-#define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, (UiToggleArgs){ __VA_ARGS__ } )
+#define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } )
+#define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_checkbox(obj, ...) ui_checkbox_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_switch(obj, ...) ui_switch_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args);
-UIEXPORT UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args);
-UIEXPORT UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args);
+UIEXPORT UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args);
+UIEXPORT UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/container.h
--- a/ui/ui/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -59,7 +59,7 @@
typedef struct UiContainerArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -81,7 +81,7 @@
} UiContainerArgs;
typedef struct UiFrameArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -104,7 +104,7 @@
} UiFrameArgs;
typedef struct UiTabViewArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -116,6 +116,8 @@
const char *style_class;
UiTabViewType tabview;
+ ui_callback onchange;
+ void *onchangedata;
UiSubContainerType subcontainer;
@@ -132,7 +134,7 @@
} UiTabViewArgs;
typedef struct UiHeaderbarArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -158,7 +160,7 @@
} UiSidebarArgs;
typedef struct UiSplitPaneArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -181,7 +183,7 @@
} UiSplitPaneArgs;
typedef struct UiItemListContainerArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -235,39 +237,39 @@
#define UI_CTN(obj, ctn) for(ctn;ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vbox(obj, ...) for(ui_vbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hbox(obj, ...) for(ui_hbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_grid(obj, ...) for(ui_grid_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_frame(obj, ...) for(ui_frame_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_expander(obj, ...) for(ui_expander_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_tabview(obj, ...) for(ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, (UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vbox(obj, ...) for(ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hbox(obj, ...) for(ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_grid(obj, ...) for(ui_grid_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_frame(obj, ...) for(ui_frame_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_expander(obj, ...) for(ui_expander_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_tabview(obj, ...) for(ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, &(UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vbox0(obj) for(ui_vbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hbox0(obj) for(ui_hbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_grid0(obj) for(ui_grid_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_frame0(obj) for(ui_frame_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_expander0(obj) for(ui_expande_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_tabview0(obj) for(ui_tabview_create(obj, (UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_headerbar0(obj) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_sidebar0(obj) for(ui_sidebar_create(obj, (UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vbox0(obj) for(ui_vbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hbox0(obj) for(ui_hbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_grid0(obj) for(ui_grid_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_frame0(obj) for(ui_frame_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_expander0(obj) for(ui_expande_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, &(UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_tabview0(obj) for(ui_tabview_create(obj, &(UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_headerbar0(obj) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_sidebar0(obj) for(ui_sidebar_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_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_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))
-#define ui_vsplitpane0(obj) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ 0 });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))
+#define ui_vsplitpane0(obj) for(ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_hsplitpane_w(obj, w, ...) for(w = ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_vsplitpane_w(obj, w, ...) for(w = ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hsplitpane_w(obj, w, ...) for(w = ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vsplitpane_w(obj, w, ...) for(w = ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_tab(obj, label) for(ui_tab_create(obj, label);ui_container_finish(obj);ui_container_begin_close(obj))
@@ -275,35 +277,35 @@
#define ui_headerbar_center(obj) for(ui_headerbar_center_create(obj);ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_headerbar_end(obj) for(ui_headerbar_end_create(obj);ui_container_finish(obj);ui_container_begin_close(obj))
-#define ui_itemlist(obj, ...) ui_itemlist_create(obj, (UiItemListContainerArgs) { __VA_ARGS__} )
+#define ui_itemlist(obj, ...) ui_itemlist_create(obj, &(UiItemListContainerArgs) { __VA_ARGS__} )
UIEXPORT void ui_end(UiObject *obj); // deprecated
UIEXPORT void ui_end_new(UiObject *obj); // TODO: rename to ui_end
-UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args);
-UIEXPORT UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args);
-UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args);
-UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs args);
+UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args);
+UIEXPORT UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args);
+UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args);
+UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs *args);
-UIEXPORT UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs args);
+UIEXPORT UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args);
UIEXPORT void ui_tab_create(UiObject *obj, const char* title);
UIEXPORT void ui_tabview_select(UIWIDGET tabview, int tab);
UIEXPORT void ui_tabview_remove(UIWIDGET tabview, int tab);
UIEXPORT UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index);
-UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args);
+UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args);
UIEXPORT void ui_headerbar_start_create(UiObject *obj);
UIEXPORT void ui_headerbar_center_create(UiObject *obj);
UIEXPORT void ui_headerbar_end_create(UiObject *obj);
-UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args);
+UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args);
-UIEXPORT UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args);
+UIEXPORT UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args);
-UIEXPORT UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args);
-UIEXPORT UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args);
+UIEXPORT UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args);
+UIEXPORT UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args);
UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBool visible);
@@ -342,6 +344,17 @@
if(args.rowspan > 0) ui_layout_rowspan(obj, args.rowspan); \
/*force caller to add ';'*/(void)0
+#define UI_APPLY_LAYOUT2(obj, args) \
+ if(args->fill != UI_DEFAULT) ui_layout_fill(obj, args->fill == UI_ON ? 1 : 0 ); \
+ if(args->hexpand) ui_layout_hexpand(obj, 1); \
+ if(args->vexpand) ui_layout_vexpand(obj, 1); \
+ if(args->hfill) ui_layout_hfill(obj, 1); \
+ if(args->vfill) ui_layout_vfill(obj, 1); \
+ if(args->override_defaults) ui_layout_override_defaults(obj, 1); \
+ if(args->colspan > 0) ui_layout_colspan(obj, args->colspan); \
+ if(args->rowspan > 0) ui_layout_rowspan(obj, args->rowspan); \
+ /*force caller to add ';'*/(void)0
+
#ifdef __cplusplus
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/display.h
--- a/ui/ui/display.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/display.h Sun Jul 20 22:04:39 2025 +0200
@@ -58,7 +58,7 @@
typedef enum UiLabelStyle UiLabelStyle;
typedef struct UiLabelArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -77,7 +77,7 @@
} UiLabelArgs;
typedef struct UiProgressbarArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -96,7 +96,7 @@
} UiProgressbarArgs;
typedef struct UiProgressbarSpinnerArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -113,24 +113,24 @@
/* label widgets */
-#define ui_label(obj, ...) ui_label_create(obj, (UiLabelArgs) { __VA_ARGS__ })
-#define ui_llabel(obj, ...) ui_llabel_create(obj, (UiLabelArgs) { __VA_ARGS__ })
-#define ui_rlabel(obj, ...) ui_rlabel_create(obj, (UiLabelArgs) { __VA_ARGS__ })
+#define ui_label(obj, ...) ui_label_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
+#define ui_llabel(obj, ...) ui_llabel_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
+#define ui_rlabel(obj, ...) ui_rlabel_create(obj, &(UiLabelArgs) { __VA_ARGS__ })
-UIEXPORT UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs args);
-UIEXPORT UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args);
-UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args);
+UIEXPORT UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs *args);
+UIEXPORT UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args);
+UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args);
UIWIDGET ui_space_deprecated(UiObject *obj);
/* progress bar/spinner */
-#define ui_progressbar(obj, ...) ui_progressbar_create(obj, (UiProgressbarArgs) { __VA_ARGS__ } )
-#define ui_progressspinner(obj, ...) ui_progressspinner_create(obj, (UiProgressbarSpinnerArgs) { __VA_ARGS__ } )
+#define ui_progressbar(obj, ...) ui_progressbar_create(obj, &(UiProgressbarArgs) { __VA_ARGS__ } )
+#define ui_progressspinner(obj, ...) ui_progressspinner_create(obj, &(UiProgressbarSpinnerArgs) { __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args);
-UIEXPORT UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args);
+UIEXPORT UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args);
+UIEXPORT UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args);
#ifdef __cplusplus
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/entry.h
--- a/ui/ui/entry.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/entry.h Sun Jul 20 22:04:39 2025 +0200
@@ -37,7 +37,7 @@
typedef struct UiSpinnerArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -62,9 +62,9 @@
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs args);
+UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args);
-#define ui_spinner(obj, ...) ui_spinner_create(obj, (UiSpinnerArgs){ __VA_ARGS__ } )
+#define ui_spinner(obj, ...) ui_spinner_create(obj, &(UiSpinnerArgs){ __VA_ARGS__ } )
void ui_spinner_setrange(UIWIDGET spinner, double min, double max);
void ui_spinner_setdigits(UIWIDGET spinner, int digits);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/icons.h
--- a/ui/ui/icons.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/icons.h Sun Jul 20 22:04:39 2025 +0200
@@ -49,6 +49,8 @@
#define UI_ICON_DOCK_RIGHT ""
#define UI_ICON_GO_BACK "go-previous"
#define UI_ICON_GO_FORWARD "go-next"
+#define UI_ICON_GO_UP "go-up"
+#define UI_ICON_GO_DOWN "go-down"
#endif /* UI_GTK */
@@ -68,6 +70,8 @@
#define UI_ICON_DOCK_RIGHT "DockRight"
#define UI_ICON_GO_BACK "Back"
#define UI_ICON_GO_FORWARD "Forward"
+#define UI_ICON_GO_UP "Up"
+#define UI_ICON_GO_DOWN "" // TODO: implement workaround for missing down symbol
#endif /* UI_WINUI */
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/image.h
--- a/ui/ui/image.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/image.h Sun Jul 20 22:04:39 2025 +0200
@@ -45,7 +45,7 @@
typedef struct UiImageViewerArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -75,9 +75,9 @@
void *onbuttonreleasedata;
} UiImageViewerArgs;
-#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } )
+#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, &(UiImageViewerArgs){ __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args);
+UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args);
UIEXPORT UIWIDGET ui_imageviewer_reset(UIWIDGET w);
UIEXPORT UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set);
@@ -85,6 +85,7 @@
UIEXPORT UIWIDGET ui_imageviewer_set_useradjustable(UIWIDGET w, UiBool set);
UIEXPORT int ui_image_load_file(UiGeneric *obj, const char *path);
+UIEXPORT int ui_image_load_data(UiGeneric *obj, const void *imgdata, size_t size);
UIEXPORT void ui_image_ref(UIIMAGE img);
UIEXPORT void ui_image_unref(UIIMAGE img);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/menu.h
--- a/ui/ui/menu.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/menu.h Sun Jul 20 22:04:39 2025 +0200
@@ -69,23 +69,23 @@
#define ui_menu(label) for(ui_menu_create(label);ui_menu_is_open();ui_menu_close())
-#define ui_menuitem(...) ui_menuitem_create((UiMenuItemArgs){ __VA_ARGS__ })
-#define ui_menu_toggleitem(...) ui_menu_toggleitem_create((UiMenuToggleItemArgs){ __VA_ARGS__ })
-#define ui_menu_radioitem(...) ui_menu_radioitem_create((UiMenuToggleItemArgs){ __VA_ARGS__ })
-#define ui_menu_itemlist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS__ } )
-#define ui_menu_togglelist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS} )
-#define ui_menu_radiolist(...) ui_menu_itemlist_create((UiMenuItemListArgs) { __VA_ARGS} )
+#define ui_menuitem(...) ui_menuitem_create(&(UiMenuItemArgs){ __VA_ARGS__ })
+#define ui_menu_toggleitem(...) ui_menu_toggleitem_create(&(UiMenuToggleItemArgs){ __VA_ARGS__ })
+#define ui_menu_radioitem(...) ui_menu_radioitem_create(&(UiMenuToggleItemArgs){ __VA_ARGS__ })
+#define ui_menu_itemlist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS__ } )
+#define ui_menu_togglelist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS} )
+#define ui_menu_radiolist(...) ui_menu_itemlist_create(&(UiMenuItemListArgs) { __VA_ARGS} )
UIEXPORT void ui_menu_create(const char* label);
-UIEXPORT void ui_menuitem_create(UiMenuItemArgs args);
-UIEXPORT void ui_menu_toggleitem_create(UiMenuToggleItemArgs args);
-UIEXPORT void ui_menu_radioitem_create(UiMenuToggleItemArgs args);
+UIEXPORT void ui_menuitem_create(UiMenuItemArgs *args);
+UIEXPORT void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args);
+UIEXPORT void ui_menu_radioitem_create(UiMenuToggleItemArgs *args);
UIEXPORT void ui_menuseparator();
-UIEXPORT void ui_menu_itemlist_create(UiMenuItemListArgs args);
-UIEXPORT void ui_menu_toggleitemlist_create(UiMenuItemListArgs args);
-UIEXPORT void ui_menu_radioitemlist_create(UiMenuItemListArgs args);
+UIEXPORT void ui_menu_itemlist_create(UiMenuItemListArgs *args);
+UIEXPORT void ui_menu_toggleitemlist_create(UiMenuItemListArgs *args);
+UIEXPORT void ui_menu_radioitemlist_create(UiMenuItemListArgs *args);
UIEXPORT void ui_menu_end(void); // TODO: private
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/text.h
--- a/ui/ui/text.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/text.h Sun Jul 20 22:04:39 2025 +0200
@@ -36,7 +36,7 @@
#endif
typedef struct UiTextAreaArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -57,7 +57,7 @@
} UiTextAreaArgs;
typedef struct UiTextFieldArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -91,7 +91,7 @@
typedef struct UiPathTextFieldArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -119,25 +119,25 @@
void *ondropsdata;
} UiPathTextFieldArgs;
-#define ui_textarea(obj, ...) ui_textarea_create(obj, (UiTextAreaArgs) { __VA_ARGS__ })
+#define ui_textarea(obj, ...) ui_textarea_create(obj, &(UiTextAreaArgs) { __VA_ARGS__ })
-UIEXPORT UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args);
+UIEXPORT UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args);
UIEXPORT UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea);
UIEXPORT void ui_text_undo(UiText *value);
UIEXPORT void ui_text_redo(UiText *value);
-#define ui_textfield(obj, ...) ui_textfield_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, (UiTextFieldArgs) { __VA_ARGS__ })
-#define ui_path_textfield(obj, ...) ui_path_textfield_create(obj, (UiPathTextFieldArgs) { __VA_ARGS__ } )
+#define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ })
+#define ui_path_textfield(obj, ...) ui_path_textfield_create(obj, &(UiPathTextFieldArgs) { __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args);
-UIEXPORT UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args);
-UIEXPORT UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args);
+UIEXPORT UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args);
+UIEXPORT UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs *args);
+UIEXPORT UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args);
-UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args);
+UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args);
#ifdef __cplusplus
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/toolbar.h
--- a/ui/ui/toolbar.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/toolbar.h Sun Jul 20 22:04:39 2025 +0200
@@ -71,16 +71,16 @@
UI_TOOLBAR_RIGHT
};
-#define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, (UiToolbarItemArgs){ __VA_ARGS__ } )
-#define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, (UiToolbarToggleItemArgs){ __VA_ARGS__ } )
+#define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, &(UiToolbarItemArgs){ __VA_ARGS__ } )
+#define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } )
-#define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, (UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close())
-#define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, (UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close())
+#define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, &(UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close())
+#define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, &(UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close())
-UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args);
-UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs args);
-UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs args);
+UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args);
+UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args);
+UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args);
UIEXPORT void ui_toolbar_add_default(const char *name, enum UiToolbarPos pos);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/toolkit.h
--- a/ui/ui/toolkit.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/toolkit.h Sun Jul 20 22:04:39 2025 +0200
@@ -92,7 +92,11 @@
#define UIEXPORT __declspec(dllexport)
-#define UIWIDGET void*
+typedef struct W32Widget {
+ HWND hwnd;
+} W32Widget;
+
+#define UIWIDGET W32Widget*
#define UIWINDOW void*
#define UIMENU void*
@@ -217,7 +221,6 @@
UI_OFF
} UiTri;
-
enum UiMouseEventType { UI_PRESS = 0, UI_PRESS2 };
typedef enum UiLabelType {
@@ -237,7 +240,8 @@
typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
-typedef void*(*ui_getvaluefunc)(void*, int);
+typedef void*(*ui_getvaluefunc)(void *elm, int col);
+typedef void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult);
typedef int(*ui_threadfunc)(void*);
@@ -318,6 +322,7 @@
void *document;
void *window;
void *eventdata;
+ int eventdatatype;
int intval;
int set;
};
@@ -405,6 +410,8 @@
UiObserver *observers;
};
+typedef void (*ui_list_init_func)(UiContext *ctx, UiList *list, void *userdata);
+
/*
* abstract list
*/
@@ -470,6 +477,22 @@
int intdata;
} UiCondVar;
+enum UiEventType {
+ UI_EVENT_DATA_NULL = 0,
+ UI_EVENT_DATA_POINTER,
+ UI_EVENT_DATA_STRING,
+ UI_EVENT_DATA_INTEGER_VALUE,
+ UI_EVENT_DATA_STRING_VALUE,
+ UI_EVENT_DATA_TEXT_VALUE,
+ UI_EVENT_DATA_DOUBLE_VALUE,
+ UI_EVENT_DATA_RANGE_VALUE,
+ UI_EVENT_DATA_LIST_SELECTION,
+ UI_EVENT_DATA_LIST_ELM,
+ UI_EVENT_DATA_DND,
+ UI_EVENT_DATA_SUBLIST,
+ UI_EVENT_DATA_FILE_LIST
+};
+
UIEXPORT void ui_init(const char *appname, int argc, char **argv);
UIEXPORT const char* ui_appname();
@@ -482,6 +505,8 @@
UIEXPORT void ui_context_destroy(UiContext *ctx);
+UIEXPORT UiContext* ui_context_parent(UiContext *ctx);
+
UIEXPORT void ui_object_ref(UiObject *obj);
UIEXPORT int ui_object_unref(UiObject *obj);
@@ -489,6 +514,9 @@
UIEXPORT void ui_onopen(ui_callback f, void *userdata);
UIEXPORT void ui_onexit(ui_callback f, void *userdata);
+UIEXPORT int ui_app_save_settings(void);
+UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
+
UIEXPORT void ui_main(void);
UIEXPORT void ui_show(UiObject *obj);
UIEXPORT void ui_close(UiObject *obj);
@@ -502,17 +530,12 @@
UIEXPORT void* ui_document_new(size_t size);
UIEXPORT void ui_document_destroy(void *doc);
-UIEXPORT void ui_set_document(UiObject *obj, void *document); // deprecated
-UIEXPORT void ui_detach_document(UiObject *obj); // deprecated
-UIEXPORT void* ui_get_document(UiObject *obj); // deprecated
-UIEXPORT void ui_set_subdocument(void *document, void *sub); // deprecated
-UIEXPORT void ui_detach_subdocument(void *document, void *sub); // deprecated
UIEXPORT void* ui_get_subdocument(void *document); // deprecated
UIEXPORT UiContext* ui_document_context(void *doc);
UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
-UIEXPORT void ui_detach_document2(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, ...);
@@ -531,12 +554,12 @@
// types
-UIEXPORT UiInteger* ui_int_new(UiContext *ctx, char *name);
-UIEXPORT UiDouble* ui_double_new(UiContext *ctx, char *name);
-UIEXPORT UiString* ui_string_new(UiContext *ctx, char *name);
-UIEXPORT UiText* ui_text_new(UiContext *ctx, char *name);
-UIEXPORT UiRange* ui_range_new(UiContext *ctx, char *name);
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name);
+UIEXPORT UiInteger* ui_int_new(UiContext *ctx, const char *name);
+UIEXPORT UiDouble* ui_double_new(UiContext *ctx, const char *name);
+UIEXPORT UiString* ui_string_new(UiContext *ctx, const char *name);
+UIEXPORT UiText* ui_text_new(UiContext *ctx, const char *name);
+UIEXPORT UiRange* ui_range_new(UiContext *ctx, const char *name);
+UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name);
#define ui_get(v) _Generic(v, \
UiInteger*: ui_int_get, \
@@ -558,6 +581,8 @@
UIEXPORT char* ui_string_get(UiString *s);
UIEXPORT void ui_text_set(UiText *s, const char* value);
UIEXPORT char* ui_text_get(UiText *s);
+UIEXPORT void ui_generic_set_image(UiGeneric *g, void *img);
+UIEXPORT void* ui_generic_get_image(UiGeneric *g);
UIEXPORT void ui_var_set_int(UiContext *ctx, const char *name, int64_t value);
UIEXPORT int64_t ui_var_get_int(UiContext *ctx, const char *name);
@@ -574,7 +599,8 @@
UIEXPORT void ui_notify_evt(UiObserver *observer, UiEvent *event);
-UIEXPORT UiList* ui_list_new(UiContext *ctx, char *name);
+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_first(UiList *list);
UIEXPORT void* ui_list_next(UiList *list);
@@ -624,6 +650,15 @@
UIEXPORT void ui_setop_enable(int set);
UIEXPORT int ui_get_setop(void);
+
+UIEXPORT void ui_global_list_initializer(ui_list_init_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));
+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);
+
#ifdef __cplusplus
}
#endif
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/tree.h
--- a/ui/ui/tree.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/tree.h Sun Jul 20 22:04:39 2025 +0200
@@ -78,12 +78,23 @@
int *columnsize;
/*
+ * void*(*ui_getvaluefunc)(void *elm, int col);
+ *
* function for translating model data to view data
- * first argument is the pointer returned by UiList->get or UiTree->get
+ * first argument is the pointer returned by UiList first|next|get
* second argument is the column index
* TODO: return
*/
- void*(*getvalue)(void*, int);
+ ui_getvaluefunc getvalue;
+
+ /*
+ * void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata)
+ *
+ * alternative for getvalue
+ */
+ ui_getvaluefunc2 getvalue2;
+
+ void *getvalue2data;
};
struct UiListCallbacks {
@@ -104,7 +115,7 @@
};
struct UiListArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -121,6 +132,8 @@
char **static_elements;
size_t static_nelm;
ui_getvaluefunc getvalue;
+ ui_getvaluefunc2 getvalue2;
+ void *getvalue2data;
ui_callback onactivate;
void* onactivatedata;
ui_callback onselection;
@@ -130,14 +143,14 @@
ui_callback ondragcomplete;
void* ondragcompletedata;
ui_callback ondrop;
- void* ondropsdata;
+ void* ondropdata;
UiBool multiselection;
UiMenuBuilder *contextmenu;
const int *groups;
};
-typedef void (*ui_sublist_getvalue_func)(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item);
+typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
struct UiSubList {
UiList *value;
@@ -171,7 +184,7 @@
};
struct UiSourceListArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -220,6 +233,11 @@
ui_sublist_getvalue_func getvalue;
/*
+ * getvalue_func userdata
+ */
+ void *getvaluedata;
+
+ /*
* activated when a list item is selected
*/
ui_callback onactivate;
@@ -240,21 +258,28 @@
UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
UIEXPORT void ui_model_free(UiContext *ctx, 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_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, (UiListArgs) { __VA_ARGS__ } )
-#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, (UiSourceListArgs) { __VA_ARGS__ } )
+#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_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(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args);
-UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args);
+UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_combobox_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 UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args);
+UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args);
+
+UIEXPORT void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon);
+UIEXPORT void ui_sublist_item_set_label(UiSubListItem *item, const char *label);
+UIEXPORT void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon);
+UIEXPORT void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label);
+UIEXPORT void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge);
+UIEXPORT void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata);
#ifdef __cplusplus
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/webview.h
--- a/ui/ui/webview.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/webview.h Sun Jul 20 22:04:39 2025 +0200
@@ -56,9 +56,9 @@
const int* groups;
} UiWebviewArgs;
-#define ui_webview(obj, ...) ui_webview_create(obj, (UiWebviewArgs){ __VA_ARGS__ } )
+#define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs args);
+UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
void ui_webview_load_url(UiGeneric *g, const char *url);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/widget.h
--- a/ui/ui/widget.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/widget.h Sun Jul 20 22:04:39 2025 +0200
@@ -35,7 +35,7 @@
#endif
typedef struct UiWidgetArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
@@ -48,21 +48,21 @@
} UiWidgetArgs;
#ifdef UI_GTK
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
#elif defined(UI_QT)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
#elif defined(UI_MOTIF)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata, Widget parent, Arg *a, int n);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata, Widget parent, Arg *a, int n);
#elif defined(UI_COCOA)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
#elif defined(UI_WINUI)
-typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+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);
+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);
+UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args);
-#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, (UiWidgetArgs) { __VA_ARGS__ })
+#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, &(UiWidgetArgs) { __VA_ARGS__ })
UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);
diff -r b34bd1557c6c -r 77254bd6dccb ui/ui/window.h
--- a/ui/ui/window.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/ui/window.h Sun Jul 20 22:04:39 2025 +0200
@@ -75,16 +75,16 @@
UIEXPORT UiObject *ui_window(const char *title, void *window_data);
UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data);
UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data);
-UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args);
+UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args);
-#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, (UiDialogWindowArgs){ __VA_ARGS__ });
-#define ui_dialog_window0(parent) ui_dialog_window_create(parent, (UiDialogWindowArgs){ 0 });
+#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ __VA_ARGS__ });
+#define ui_dialog_window0(parent) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ 0 });
UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
-#define ui_dialog(parent, ...) ui_dialog_create(parent, (UiDialogArgs){ __VA_ARGS__ } )
+#define ui_dialog(parent, ...) ui_dialog_create(parent, &(UiDialogArgs){ __VA_ARGS__ } )
-UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs args);
+UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs *args);
UIEXPORT void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata);
UIEXPORT void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata);
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/Makefile
--- a/ui/win32/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/win32/Makefile Sun Jul 20 22:04:39 2025 +0200
@@ -31,3 +31,6 @@
$(UI_LIB): $(OBJ)
$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
+
+$(UI_SHLIB): $(OBJ)
+ $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/$(BUILD_LIB_DIR) -lucx
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/button.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/button.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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 "button.h"
+
+UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
+ return NULL;
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/button.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/button.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 BUTTON_H
+#define BUTTON_H
+
+#include "../ui/button.h"
+#include "container.h"
+
+#endif //BUTTON_H
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/container.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/container.c Sun Jul 20 22:04:39 2025 +0200
@@ -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.
+ */
+
+#include "container.h"
+
+
+/* ---------------------------- Box Container ---------------------------- */
+
+static UIWIDGET box_create(UiObject *obj, UiContainerArgs *args, UiBoxOrientation orientation) {
+ return NULL;
+}
+
+// public
+UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
+ return box_create(obj, args, UI_BOX_VERTICAL);
+}
+
+// public
+UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) {
+ return box_create(obj, args, UI_BOX_HORIZONTAL);
+}
+
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/container.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -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 CONTAINER_H
+
+#include "../ui/container.h"
+
+#define CONTAINER_H
+
+#define UI_APPLY_LAYOUT(layout, args) \
+ layout.fill = args->fill; \
+ layout.hexpand = args->hexpand; \
+ layout.vexpand = args->vexpand; \
+ layout.hfill = args->hfill; \
+ layout.vfill = args->vfill; \
+ layout.override_defaults = args->override_defaults; \
+ layout.colspan = args->colspan; \
+ layout.rowspan = args->rowspan
+
+typedef struct UiLayout UiLayout;
+
+struct UiLayout {
+ UiBool fill;
+ UiBool newline;
+ char *label;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int width;
+ int colspan;
+ int rowspan;
+};
+
+enum UiBoxOrientation {
+ UI_BOX_VERTICAL = 0,
+ UI_BOX_HORIZONTAL
+};
+typedef enum UiBoxOrientation UiBoxOrientation;
+
+enum UiContainerType {
+ UI_CONTAINER_GENERIC = 0,
+ UI_CONTAINER_TABVIEW
+};
+typedef enum UiContainerType UiContainerType;
+
+typedef struct UiContainerPrivate UiContainerPrivate;
+
+typedef struct UiRect {
+ int x;
+ int y;
+ int width;
+ int height;
+} UiRect;
+
+
+struct UiContainerPrivate {
+ UiContainerX container;
+ void (*prepare)(UiContainerPrivate*, UiRect*);
+ void (*add)(UiContainerPrivate*, UiRect*, W32Widget*);
+ UiContainerType type;
+ UiLayout layout;
+};
+
+#endif //CONTAINER_H
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/grid.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/grid.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,61 @@
+/*
+* 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 "grid.h"
+
+#include "../../ucx/cx/array_list.h"
+#include "../common/context.h"
+
+UiGridLayout* ui_grid_container(UiObject *obj, HWND control, short padding, short columnspacing, short rowspacing) {
+ UiGridLayout *grid = cxZalloc(obj->ctx->allocator, sizeof(UiGridLayout));
+ grid->hwnd = control;
+ grid->widgets = cxArrayListCreate(obj->ctx->allocator, NULL, sizeof(GridElm), 32);
+ grid->padding = padding;
+ grid->columnspacing = columnspacing;
+ grid->rowspacing = rowspacing;
+ return grid;
+}
+
+void ui_grid_add_widget(
+ UiGridLayout *grid,
+ short x,
+ short y,
+ W32Widget *widget,
+ GridLayoutInfo *layout)
+{
+ GridElm elm;
+ elm.widget = widget;
+ elm.x = x;
+ elm.y = y;
+ elm.layout = *layout;
+ cxListAdd(grid->widgets, elm);
+}
+
+void ui_grid_layout(UiGridLayout *grid) {
+ // TODO
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/grid.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/grid.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,82 @@
+/*
+* 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 GRID_H
+#define GRID_H
+
+#include "container.h"
+#include
+#include
+
+typedef struct GridElm {
+ W32Widget *widget;
+ short x;
+ short y;
+ GridLayoutInfo layout;
+} GridElm;
+
+typedef struct GridLayoutInfo {
+ short margin_left;
+ short margin_right;
+ short margin_top;
+ short margin_bottom;
+ short colspan;
+ short rowspan;
+ short preferred_width;
+ short preferred_height;
+ bool hexpand;
+ bool vexpand;
+ bool hfill;
+ bool vfill;
+} GridLayoutInfo;
+
+typedef struct UiGridLayout {
+ HWND hwnd;
+
+ short padding;
+ short columnspacing;
+ short rowspacing;
+
+ /*
+ * list element type: GridElm
+ */
+ CxList *widgets;
+
+} UiGridLayout;
+
+UiGridLayout* ui_grid_container(UiObject *obj, HWND control, short padding, short columnspacing, short rowspacing);
+
+void ui_grid_add_widget(
+ UiGridLayout *grid,
+ short x,
+ short y,
+ W32Widget *widget,
+ GridLayoutInfo *layout);
+
+void ui_grid_layout(UiGridLayout *grid);
+
+#endif //GRID_H
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/image.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/image.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,37 @@
+/*
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 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 "image.h"
+
+void ui_image_ref(UIIMAGE img) {
+ // TODO
+}
+
+void ui_image_unref(UIIMAGE img) {
+ // TODO
+}
\ No newline at end of file
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/image.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/image.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,42 @@
+/*
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 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 IMAGE_H
+#define IMAGE_H
+
+#include "../ui/image.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IMAGE_H
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/objs.mk
--- a/ui/win32/objs.mk Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/win32/objs.mk Sun Jul 20 22:04:39 2025 +0200
@@ -29,7 +29,11 @@
WIN32_SRC_DIR = ui/win32/
WIN32_OBJPRE = $(OBJ_DIR)$(WIN32_SRC_DIR)
-WIN32OBJ = toolkit.obj
+WIN32OBJ = toolkit.obj
+WIN32OBJ += window.obj
+WIN32OBJ += image.obj
+WIN32OBJ += container.obj
+WIN32OBJ += button.obj
TOOLKITOBJS += $(WIN32OBJ:%=$(WIN32_OBJPRE)%)
TOOLKITSOURCE += $(WIN32OBJ:%.obj=win32/%.c)
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/toolkit.c
--- a/ui/win32/toolkit.c Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/win32/toolkit.c Sun Jul 20 22:04:39 2025 +0200
@@ -29,6 +29,11 @@
#include "toolkit.h"
#include "Windows.h"
+#include "window.h"
+
+#include "../common/menu.h"
+#include "../common/toolbar.h"
+#include "../common/document.h"
#include "../common/properties.h"
#include
@@ -44,7 +49,15 @@
void *exit_data;
void ui_init(const char *appname, int argc, char **argv) {
- application_name = appname;
+ application_name = appname;
+
+ uic_init_global_context();
+ uic_docmgr_init();
+ uic_menu_init();
+ uic_toolbar_init();
+ uic_load_app_properties();
+
+ ui_window_init();
}
const char* ui_appname() {
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/window.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/window.c Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 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 "window.h"
+#include "Windows.h"
+
+#include "../common/object.h"
+
+
+#include
+#include
+#include
+
+
+static HINSTANCE hInstance;
+
+static const char *mainWindowClass = "UiMainWindow";
+
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch(uMsg) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ default:
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ return 0;
+}
+
+void ui_window_init(void) {
+ hInstance = GetModuleHandle(NULL);
+
+ WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = mainWindowClass;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+
+ if(!RegisterClassExA(&wc)) {
+ MessageBox(NULL, "RegisterClassEx failed", "Error", MB_ICONERROR);
+ exit(-1);
+ }
+}
+
+static UiObject* create_window(const char *title, void *window_data, bool simple) {
+ UiObject *obj = uic_object_new_toplevel();
+ obj->window = window_data;
+
+ HWND hwnd = CreateWindowExA(
+ 0,
+ "UiMainWindow",
+ title,
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 800,
+ 600,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ UpdateWindow(hwnd);
+
+ return obj;
+}
+
+UiObject *ui_window(const char *title, void *window_data) {
+ return create_window(title, window_data, FALSE);
+}
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/win32/window.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/win32/window.h Sun Jul 20 22:04:39 2025 +0200
@@ -0,0 +1,51 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include
+#include "../ui/window.h"
+#include "../common/context.h"
+#include "../common/object.h"
+
+#include "toolkit.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ui_window_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WINDOW_H */
+
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/container.cpp
--- a/ui/winui/container.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/container.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -34,6 +34,7 @@
#include "../common/object.h"
#include "util.h"
+#include "../ui/widget.h"
void ui_container_begin_close(UiObject* obj) {
@@ -51,13 +52,13 @@
}
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
UiObject* current = uic_current_obj(obj);
UIWIDGET widget = create_widget(obj, args, userdata);
FrameworkElement w = widget->uielement.as();
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->Add(w, false);
@@ -66,9 +67,9 @@
// --------------------- UiBoxContainer ---------------------
-static UIWIDGET ui_box(UiObject* obj, UiContainerArgs args, UiBoxContainerType type) {
+static UIWIDGET ui_box(UiObject* obj, UiContainerArgs *args, UiBoxContainerType type) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
Grid grid = Grid();
current->container->Add(grid, true);
@@ -78,18 +79,18 @@
ui_context_add_widget_destructor(current->ctx, widget);
UiObject* newobj = uic_object_new(obj, widget);
- newobj->container = new UiBoxContainer(grid, type, args.margin, args.spacing);
+ newobj->container = new UiBoxContainer(grid, type, args->margin, args->spacing);
ui_context_add_container_destructor(current->ctx, newobj->container);
uic_obj_add(obj, newobj);
return widget;
}
-UIWIDGET ui_vbox_create(UiObject* obj, UiContainerArgs args) {
+UIWIDGET ui_vbox_create(UiObject* obj, UiContainerArgs *args) {
return ui_box(obj, args, UI_BOX_CONTAINER_VBOX);
}
-UIWIDGET ui_hbox_create(UiObject* obj, UiContainerArgs args) {
+UIWIDGET ui_hbox_create(UiObject* obj, UiContainerArgs *args) {
return ui_box(obj, args, UI_BOX_CONTAINER_HBOX);
}
@@ -161,9 +162,9 @@
// --------------------- UiGridContainer ---------------------
-UIWIDGET ui_grid_create(UiObject* obj, UiContainerArgs args) {
+UIWIDGET ui_grid_create(UiObject* obj, UiContainerArgs *args) {
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
Grid grid = Grid();
current->container->Add(grid, true);
@@ -173,7 +174,7 @@
ui_context_add_widget_destructor(current->ctx, widget);
UiObject* newobj = uic_object_new(obj, widget);
- newobj->container = new UiGridContainer(grid, args.margin, args.columnspacing, args.rowspacing);
+ newobj->container = new UiGridContainer(grid, args->margin, args->columnspacing, args->rowspacing);
ui_context_add_container_destructor(current->ctx, newobj->container);
uic_obj_add(obj, newobj);
@@ -303,7 +304,7 @@
// --------------------- UI Frame ---------------------
-UIWIDGET ui_frame_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_frame_create(UiObject* obj, UiFrameArgs *args) {
// create a grid for the frame, that contains the label and a sub-frame
Grid frame = Grid();
@@ -320,7 +321,7 @@
// label
int row = 0;
- if (args.label) {
+ if (args->label) {
RowDefinition rowdefLabel = RowDefinition();
gl.GridUnitType = GridUnitType::Auto;
gl.Value = 0;
@@ -328,7 +329,7 @@
frame.RowDefinitions().Append(rowdefLabel);
TextBlock label = TextBlock();
- wchar_t* wlabel = str2wstr(args.label, nullptr);
+ wchar_t* wlabel = str2wstr(args->label, nullptr);
winrt::hstring hstr(wlabel);
label.Text(hstr);
free(wlabel);
@@ -359,7 +360,7 @@
// add frame to the parent container
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->Add(frame, true);
UIElement elm = frame;
@@ -368,18 +369,18 @@
// sub container
UiContainer* ctn = nullptr;
- switch (args.subcontainer) {
+ switch (args->subcontainer) {
default:
case UI_CONTAINER_VBOX: {
- ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_VBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_HBOX: {
- ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_HBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_GRID: {
- ctn = new UiGridContainer(workarea, args.margin, args.columnspacing, args.rowspacing);
+ ctn = new UiGridContainer(workarea, args->margin, args->columnspacing, args->rowspacing);
break;
}
}
@@ -394,18 +395,18 @@
// --------------------- UI Expander ---------------------
-UIWIDGET ui_expander_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_expander_create(UiObject* obj, UiFrameArgs *args) {
Expander expander = Expander();
- if (args.label) {
- wchar_t* wlabel = str2wstr(args.label, nullptr);
+ if (args->label) {
+ wchar_t* wlabel = str2wstr(args->label, nullptr);
expander.Header(box_value(wlabel));
free(wlabel);
}
- expander.IsExpanded(args.isexpanded);
+ expander.IsExpanded(args->isexpanded);
// add frame to the parent container
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->Add(expander, true);
UIElement elm = expander;
@@ -416,18 +417,18 @@
expander.Content(content);
UiContainer* ctn = nullptr;
- switch (args.subcontainer) {
+ switch (args->subcontainer) {
default:
case UI_CONTAINER_VBOX: {
- ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_HBOX: {
- ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_GRID: {
- ctn = new UiGridContainer(content, args.margin, args.columnspacing, args.rowspacing);
+ ctn = new UiGridContainer(content, args->margin, args->columnspacing, args->rowspacing);
break;
}
}
@@ -442,12 +443,12 @@
// --------------------- UI ScrolledWindow ---------------------
-UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) {
+UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
ScrollViewer scrollW = ScrollViewer();
// add frame to the parent container
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->Add(scrollW, true);
UIElement elm = scrollW;
@@ -459,18 +460,18 @@
scrollW.Content(content);
UiContainer* ctn = nullptr;
- switch (args.subcontainer) {
+ switch (args->subcontainer) {
default:
case UI_CONTAINER_VBOX: {
- ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_HBOX: {
- ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing);
+ ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args->margin, args->spacing);
break;
}
case UI_CONTAINER_GRID: {
- ctn = new UiGridContainer(content, args.margin, args.columnspacing, args.rowspacing);
+ ctn = new UiGridContainer(content, args->margin, args->columnspacing, args->rowspacing);
break;
}
}
@@ -520,21 +521,21 @@
return newobj;
}
-static UiTabView* tabview_pivot_create(UiObject* obj, UiTabViewArgs args) {
+static UiTabView* tabview_pivot_create(UiObject* obj, UiTabViewArgs *args) {
Pivot pivot = Pivot();
UiPivotTabView* tabview = new UiPivotTabView(obj, pivot, args);
return tabview;
}
-UiPivotTabView::UiPivotTabView(UiObject* obj, Pivot pivot, UiTabViewArgs args) {
+UiPivotTabView::UiPivotTabView(UiObject* obj, Pivot pivot, UiTabViewArgs *args) {
this->current = obj;
this->pivot = pivot;
- this->subcontainer = args.subcontainer;
- this->margin = args.margin;
- this->spacing = args.spacing;
- this->columnspacing = args.columnspacing;
- this->rowspacing = args.rowspacing;
+ this->subcontainer = args->subcontainer;
+ this->margin = args->margin;
+ this->spacing = args->spacing;
+ this->columnspacing = args->columnspacing;
+ this->rowspacing = args->rowspacing;
}
UiObject* UiPivotTabView::AddTab(const char* label, int index) {
@@ -568,7 +569,7 @@
}
-static UiTabView* tabview_invisible_create(UiObject *obj, UiTabViewArgs args) {
+static UiTabView* tabview_invisible_create(UiObject *obj, UiTabViewArgs *args) {
Grid container = Grid();
container.HorizontalAlignment(HorizontalAlignment::Stretch);
container.VerticalAlignment(VerticalAlignment::Stretch);
@@ -576,14 +577,14 @@
return tabview;
}
-UiInvisibleTabView::UiInvisibleTabView(UiObject* obj, Grid container, UiTabViewArgs args) {
+UiInvisibleTabView::UiInvisibleTabView(UiObject* obj, Grid container, UiTabViewArgs *args) {
this->current = obj;
this->container = container;
- this->subcontainer = args.subcontainer;
- this->margin = args.margin;
- this->spacing = args.spacing;
- this->columnspacing = args.columnspacing;
- this->rowspacing = args.rowspacing;
+ this->subcontainer = args->subcontainer;
+ this->margin = args->margin;
+ this->spacing = args->spacing;
+ this->columnspacing = args->columnspacing;
+ this->rowspacing = args->rowspacing;
this->currentIndex = -1;
GridLength gl;
@@ -638,7 +639,7 @@
}
-static UiTabView* tabview_main_create(UiObject* obj, UiTabViewArgs args) {
+static UiTabView* tabview_main_create(UiObject* obj, UiTabViewArgs *args) {
TabView tabview = TabView();
tabview.IsAddTabButtonVisible(false);
//tabview.CanDragTabs(false);
@@ -648,14 +649,14 @@
return uitabview;
}
-UiMainTabView::UiMainTabView(UiObject* obj, TabView tabview, UiTabViewArgs args) {
+UiMainTabView::UiMainTabView(UiObject* obj, TabView tabview, UiTabViewArgs *args) {
this->current = obj;
this->tabview = tabview;
- this->subcontainer = args.subcontainer;
- this->margin = args.margin;
- this->spacing = args.spacing;
- this->columnspacing = args.columnspacing;
- this->rowspacing = args.rowspacing;
+ this->subcontainer = args->subcontainer;
+ this->margin = args->margin;
+ this->spacing = args->spacing;
+ this->columnspacing = args->columnspacing;
+ this->rowspacing = args->rowspacing;
}
UiObject* UiMainTabView::AddTab(const char* label, int index) {
@@ -691,7 +692,7 @@
}
-static UiTabView* tabview_navigationview_create(UiObject* obj, UiTabViewArgs args, UiTabViewType type) {
+static UiTabView* tabview_navigationview_create(UiObject* obj, UiTabViewArgs *args, UiTabViewType type) {
NavigationView navigationview = NavigationView();
UiNavigationTabView* tabview = new UiNavigationTabView(obj, navigationview, args, type);
navigationview.IsBackButtonVisible(NavigationViewBackButtonVisible::Collapsed);
@@ -700,14 +701,14 @@
return tabview;
}
-UiNavigationTabView::UiNavigationTabView(UiObject* obj, NavigationView navigationview, UiTabViewArgs args, UiTabViewType type) {
+UiNavigationTabView::UiNavigationTabView(UiObject* obj, NavigationView navigationview, UiTabViewArgs *args, UiTabViewType type) {
this->current = obj;
this->navigationview = navigationview;
this->type = type;
- this->margin = args.margin;
- this->spacing = args.spacing;
- this->columnspacing = args.columnspacing;
- this->rowspacing = args.rowspacing;
+ this->margin = args->margin;
+ this->spacing = args->spacing;
+ this->columnspacing = args->columnspacing;
+ this->rowspacing = args->rowspacing;
if (type == UI_TABVIEW_NAVIGATION_TOP) {
navigationview.PaneDisplayMode(NavigationViewPaneDisplayMode::Top);
@@ -773,8 +774,8 @@
tabview->Select(value);
}
-UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
- UiTabViewType type = args.tabview == UI_TABVIEW_DEFAULT ? UI_TABVIEW_NAVIGATION_TOP2 : args.tabview;
+UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
+ UiTabViewType type = args->tabview == UI_TABVIEW_DEFAULT ? UI_TABVIEW_NAVIGATION_TOP2 : args->tabview;
UiTabView* tabview = nullptr;
switch (type) {
default: {
@@ -806,7 +807,7 @@
// add frame to the parent container
UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT1(current, args);
+ UI_APPLY_LAYOUT2(current, args);
current->container->Add(tabview->GetFrameworkElement(), true);
UIElement elm = tabview->GetFrameworkElement();
@@ -817,7 +818,7 @@
// TODO: add tabview destructor
// bind variable
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
if (var) {
UiInteger *i = (UiInteger*)var->value;
i->obj = tabview;
@@ -861,28 +862,28 @@
// TODO: replace placeholder implementation
-UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
UiContainerArgs boxargs = { };
boxargs.fill = UI_OFF;
- return ui_hbox_create(obj, boxargs);
+ return ui_hbox_create(obj, &boxargs);
}
UIEXPORT void ui_headerbar_start_create(UiObject *obj) {
UiContainerArgs boxargs = { };
boxargs.fill = UI_OFF;
- ui_hbox_create(obj, boxargs);
+ ui_hbox_create(obj, &boxargs);
}
UIEXPORT void ui_headerbar_center_create(UiObject *obj) {
UiContainerArgs boxargs = { };
boxargs.fill = UI_OFF;
- ui_hbox_create(obj, boxargs);
+ ui_hbox_create(obj, &boxargs);
}
UIEXPORT void ui_headerbar_end_create(UiObject *obj) {
UiContainerArgs boxargs = { };
boxargs.fill = UI_OFF;
- ui_hbox_create(obj, boxargs);
+ ui_hbox_create(obj, &boxargs);
}
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/container.h
--- a/ui/winui/container.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/container.h Sun Jul 20 22:04:39 2025 +0200
@@ -140,7 +140,7 @@
struct UiPivotTabView : UiTabView {
Pivot pivot;
- UiPivotTabView(UiObject *obj, Pivot pivot, UiTabViewArgs args);
+ UiPivotTabView(UiObject *obj, Pivot pivot, UiTabViewArgs *args);
UiObject* AddTab(const char* label, int index = -1);
void Remove(int index);
@@ -151,7 +151,7 @@
struct UiMainTabView : UiTabView {
TabView tabview;
- UiMainTabView(UiObject* obj, TabView tabview, UiTabViewArgs args);
+ UiMainTabView(UiObject* obj, TabView tabview, UiTabViewArgs *args);
UiObject* AddTab(const char* label, int index = -1);
void Remove(int index);
@@ -164,7 +164,7 @@
UiTabViewType type;
std::vector > pages;
- UiNavigationTabView(UiObject* obj, NavigationView navigationview, UiTabViewArgs args, UiTabViewType type);
+ UiNavigationTabView(UiObject* obj, NavigationView navigationview, UiTabViewArgs *args, UiTabViewType type);
UiObject* AddTab(const char* label, int index = -1);
void Remove(int index);
@@ -179,7 +179,7 @@
std::vector pages;
int currentIndex;
- UiInvisibleTabView(UiObject *obj, Grid container, UiTabViewArgs args);
+ UiInvisibleTabView(UiObject *obj, Grid container, UiTabViewArgs *args);
UiObject* AddTab(const char* label, int index = -1);
void Remove(int index);
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/image.cpp
--- a/ui/winui/image.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/image.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -47,6 +47,16 @@
UiImageSource::UiImageSource(winrt::Microsoft::UI::Xaml::Media::ImageSource& src) : imgsrc(src) {}
+void UiImageSource::ref() {
+ refcount++;
+}
+
+void UiImageSource::unref() {
+ if (--refcount == 0) {
+ delete this;
+ }
+}
+
UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
UiObject* current = uic_current_obj(obj);
@@ -94,9 +104,10 @@
UiImageSource *imgdata = (UiImageSource*)data;
if (g->value) {
UiImageSource *prevData = (UiImageSource*)g->value;
- delete prevData;
+ //prevData->unref();
}
g->value = imgdata;
+ //imgdata->ref();
UiWidget* widget = (UiWidget*)g->obj;
Image image = widget->uielement.as();
@@ -117,8 +128,19 @@
UiImageSource *imgdata = new UiImageSource(src);
obj->set(obj, imgdata, UI_IMAGE_OBJECT_TYPE);
+ imgdata->unref();
free(wpath);
return 0;
}
+
+void ui_image_ref(UIIMAGE img) {
+ UiImageSource* imgdata = (UiImageSource*)img;
+ imgdata->ref();
+}
+
+void ui_image_unref(UIIMAGE img) {
+ UiImageSource* imgdata = (UiImageSource*)img;
+ imgdata->unref();
+}
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/image.h
--- a/ui/winui/image.h Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/image.h Sun Jul 20 22:04:39 2025 +0200
@@ -32,10 +32,16 @@
#include "../ui/image.h"
class UiImageSource {
+ unsigned int refcount = 1;
+
public:
winrt::Microsoft::UI::Xaml::Media::ImageSource imgsrc { nullptr };
UiImageSource(winrt::Microsoft::UI::Xaml::Media::ImageSource& src);
+
+ void ref();
+
+ void unref();
};
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/text.cpp
--- a/ui/winui/text.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/text.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -68,7 +68,6 @@
if (var) {
UiText* value = (UiText*)var->value;
value->obj = widget;
- value->undomgr = NULL;
value->set = ui_textarea_set;
value->get = ui_textarea_get;
value->getsubstr = ui_textarea_getsubstr;
diff -r b34bd1557c6c -r 77254bd6dccb ui/winui/window.cpp
--- a/ui/winui/window.cpp Sat Apr 05 17:57:04 2025 +0200
+++ b/ui/winui/window.cpp Sun Jul 20 22:04:39 2025 +0200
@@ -147,8 +147,7 @@
}
UIEXPORT UiObject* ui_simple_window(const char *title, void *window_data) {
- CxMempool* mp = cxMempoolCreateSimple(256);
- UiObject* obj = (UiObject*)cxCalloc(mp->allocator, 1, sizeof(UiObject));
+ UiObject* obj = uic_object_new_toplevel();
obj->ctx = uic_context(obj, mp);
obj->window = window_data;
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/Makefile
--- a/ui/wpf/Makefile Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-#
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-#
-# Copyright 2012 Olaf Wintermann. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-
-$(WPF_OBJPRE)%.o: wpf/%.c
- $(CC) -o $@ -c $(CFLAGS) $<
-
-$(UI_LIB): $(OBJ) uiw
- $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)
-
-uiw:
- cd wpf/UIwrapper; $(MSBUILD)
- cp $(BUILD_ROOT)/build/UIwrapper/UIwrapper.dll $(BUILD_ROOT)/build/bin/
- cp $(BUILD_ROOT)/build/UIcore/UIcore.dll $(BUILD_ROOT)/build/bin/
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/Application.cs
--- a/ui/wpf/UIcore/Application.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-
-namespace UI
-{
- public class Application
- {
- private static Application instance;
-
- private System.Windows.Application application;
-
- private Thread thread;
-
- public String Name;
-
- public IApplicationCallbacks callbacks;
-
- public List Windows = new List();
- public ApplicationMenu Menu = new ApplicationMenu();
- public MainToolBar ToolBar = new MainToolBar();
-
- private Application() : base()
- {
- thread = new Thread(() => RunApplication());
- thread.SetApartmentState(ApartmentState.STA);
- }
-
- public static Application GetInstance()
- {
- if (instance == null)
- {
- instance = new Application();
- GC.KeepAlive(instance);
- }
- return instance;
- }
-
- public Thread Start()
- {
- thread.Start();
- return thread;
- }
-
- private void RunApplication()
- {
- application = new System.Windows.Application();
-
- if(callbacks != null)
- {
- callbacks.OnStartup();
- }
- application.Run();
- if(callbacks != null)
- {
- callbacks.OnExit();
- }
- }
-
- public void AddWindow(Window window)
- {
- Windows.Add(window);
- }
-
- public void RemoveWindow(Window window)
- {
- Windows.Remove(window);
- if (Windows.Count == 0)
- {
- application.Shutdown();
- }
- }
- }
-
- public class ResultExec
- {
- public T Result;
- public Func Func;
-
- public void Exec()
- {
- Result = Func.Invoke();
- }
- }
-
- public class VoidExec
- {
- public Action Action;
-
- public void Exec()
- {
- Action.Invoke();
- }
- }
-
- public interface IApplicationCallbacks
- {
- void OnStartup();
- void OnOpen();
- void OnExit();
- }
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/Container.cs
--- a/ui/wpf/UIcore/Container.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-
-namespace UI
-{
- public interface Container
- {
- Layout Layout { get; set; }
-
- void Add(UIElement control, bool fill);
- }
-
- public class Layout
- {
- public bool? Fill { get; set; }
- public bool Hexpand { get; set; }
- public bool Vexpand { get; set; }
- public bool NewLine { get; set; }
- public int GridWidth { get; set; }
- public String Label { get; set; }
-
- public Layout()
- {
- Reset();
- }
-
- public bool IsFill(bool fill)
- {
- if (Fill != null)
- {
-
- return (bool)Fill;
- }
- return fill;
- }
-
- public void Reset()
- {
- Fill = null;
- Hexpand = false;
- Vexpand = false;
- NewLine = false;
- GridWidth = 1;
- Label = null;
- }
- }
-
- public enum BoxOrientation
- {
- VERTICAL,
- HORIZONTAL
- }
-
- public class BoxContainer : Grid, Container
- {
- public Layout Layout { get; set; }
-
- private BoxOrientation Orientation;
- private int Spacing;
-
- private int x = 0;
- private int y = 0;
-
- private bool filled = false;
-
- public BoxContainer(BoxOrientation orientation, int margin, int spacing) : base()
- {
- Layout = new Layout();
- Margin = new Thickness(margin);
- Spacing = spacing;
-
- Orientation = orientation;
- if(Orientation == BoxOrientation.HORIZONTAL)
- {
- RowDefinition row = new RowDefinition();
- row.Height = new GridLength(1, GridUnitType.Star);
- RowDefinitions.Add(row);
- }
- else
- {
- ColumnDefinition col = new ColumnDefinition();
- col.Width = new GridLength(1, GridUnitType.Star);
- ColumnDefinitions.Add(col);
- }
- }
-
- public BoxContainer(Container parent, BoxOrientation orientation, int margin, int spacing) : this(orientation, margin, spacing)
- {
- parent.Add(this, true);
- }
-
- public void Add(UIElement control, bool fill)
- {
- fill = Layout.IsFill(fill);
-
- if(Orientation == BoxOrientation.HORIZONTAL)
- {
- if(Spacing > 0)
- {
- ColumnDefinition spaceCol = new ColumnDefinition();
- spaceCol.Width = new GridLength(Spacing, GridUnitType.Pixel);
- ColumnDefinitions.Add(spaceCol);
- x++;
- }
-
- ColumnDefinition col = new ColumnDefinition();
- if(filled && fill)
- {
- fill = false;
- Console.WriteLine("BoxContainer can only contain one filled control");
- }
- if(fill)
- {
- col.Width = new GridLength(1, GridUnitType.Star);
- filled = true;
- }
- else
- {
- col.Width = GridLength.Auto;
- }
- ColumnDefinitions.Add(col);
- }
- else
- {
- if (Spacing > 0)
- {
- RowDefinition spaceRow = new RowDefinition();
- spaceRow.Height = new GridLength(Spacing, GridUnitType.Pixel);
- RowDefinitions.Add(spaceRow);
- y++;
- }
-
- RowDefinition row = new RowDefinition();
- if (filled && fill)
- {
- fill = false;
- Console.WriteLine("BoxContainer can only contain one filled control");
- }
- if(fill)
- {
- row.Height = new GridLength(1, GridUnitType.Star);
- filled = true;
- }
- else
- {
- row.Height = GridLength.Auto;
- }
- RowDefinitions.Add(row);
- }
-
- Grid.SetColumn(control, x);
- Grid.SetRow(control, y);
- Children.Add(control);
-
- if(Orientation == BoxOrientation.HORIZONTAL)
- {
- x++;
- }
- else
- {
- y++;
- }
-
- Layout.Reset();
- }
- }
-
- public class GridContainer : Grid, Container
- {
- public Layout Layout { get; set; }
-
- private int X = 0;
- private int Y = 0;
- private int CurrentWidth = 0;
- private int CurrentHeight = 0;
-
- private int ColSpacing;
- private int RowSpacing;
-
- public GridContainer(Container parent, int margin, int colspacing, int rowspacing) : base()
- {
- Layout = new Layout();
-
- Margin = new Thickness(margin);
- ColSpacing = colspacing;
- RowSpacing = rowspacing;
-
- parent.Add(this, true);
- }
-
- public void Add(UIElement control, bool fill)
- {
- if(Layout.NewLine)
- {
- X = 0;
- Y++;
- }
-
- ColumnDefinition col;
- RowDefinition row;
- bool getcol = false;
- if(X >= CurrentWidth)
- {
- if (ColSpacing > 0 && X != 0)
- {
- ColumnDefinition spaceCol = new ColumnDefinition();
- spaceCol.Width = new GridLength(ColSpacing, GridUnitType.Pixel);
- ColumnDefinitions.Add(spaceCol);
- X++;
- }
-
- col = new ColumnDefinition();
- col.Width = GridLength.Auto;
- ColumnDefinitions.Add(col);
-
- CurrentWidth = X + 1;
- }
- else
- {
- if (ColSpacing > 0 && X % 2 > 0)
- {
- X++;
- }
- col = ColumnDefinitions.ElementAt(X);
- }
-
- if(getcol)
- {
- col = ColumnDefinitions.ElementAt(X);
- }
-
- if (Y >= CurrentHeight)
- {
- if (RowSpacing > 0 && Y != 0)
- {
- RowDefinition spaceRow = new RowDefinition();
- spaceRow.Height = new GridLength(RowSpacing, GridUnitType.Pixel);
- RowDefinitions.Add(spaceRow);
- Y++;
- }
-
- row = new RowDefinition();
- row.Height = GridLength.Auto;
- RowDefinitions.Add(row);
- CurrentHeight = Y + 1;
- }
- else
- {
- row = RowDefinitions.ElementAt(Y);
- }
-
- if(Layout.Hexpand)
- {
- col.Width = new GridLength(1, GridUnitType.Star);
- }
- if(Layout.Vexpand)
- {
- row.Height = new GridLength(1, GridUnitType.Star);
- }
-
- int gridwidth = Layout.GridWidth;
- if(gridwidth > 1)
- {
- gridwidth++;
- }
-
- Grid.SetColumn(control, X);
- Grid.SetRow(control, Y);
- Grid.SetColumnSpan(control, gridwidth);
- Children.Add(control);
-
- Layout.Reset();
- X += gridwidth;
- }
- }
-
- public class ScrollViewerContainer : ScrollViewer, Container
- {
- public Layout Layout { get; set; }
-
- public ScrollViewerContainer(Container parent) : base()
- {
- Layout = new Layout();
-
- HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
- VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
-
- parent.Add(this, true);
- }
-
- public void Add(UIElement control, bool fill)
- {
- Content = control;
- }
- }
-
- public class TabViewContainer : TabControl, Container
- {
- public Layout Layout { get; set; }
-
- public TabViewContainer(Container parent) : base()
- {
- Layout = new Layout();
- parent.Add(this, true);
- }
-
- public void Add(UIElement control, bool fill)
- {
- TabItem tab = new TabItem();
- tab.Header = Layout.Label != null ? Layout.Label : "New Tab";
- Items.Add(tab);
- tab.Content = control;
- Layout.Reset();
- }
- }
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/Controls.cs
--- a/ui/wpf/UIcore/Controls.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-
-namespace UI
-{
- public class Controls
- {
- public static Button Button(Container container, String label, RoutedEventHandler e)
- {
- Button button = new Button();
- button.Content = label;
- container.Add(button, false);
-
- button.Click += e;
-
- return button;
- }
-
- public static Label Label(Container container, String str, int alignment)
- {
- HorizontalAlignment a;
- switch (alignment)
- {
- case 0: a = HorizontalAlignment.Left; break;
- case 1: a = HorizontalAlignment.Right; break;
- case 2: a = HorizontalAlignment.Center; break;
- default: a = HorizontalAlignment.Left; break;
- }
-
- Label label = new Label();
- label.HorizontalAlignment = a;
- label.Content = str;
- container.Add(label, false);
-
- return label;
- }
-
- public static Label Space(Container container)
- {
- return Label(container, null, 2);
- }
-
- public static Separator Separator(Container container)
- {
- Separator separator = new Separator();
- container.Add(separator, false);
- return separator;
- }
- }
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/DrawingArea.cs
--- a/ui/wpf/UIcore/DrawingArea.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-using System.Windows.Shapes;
-using System.Diagnostics;
-
-namespace UI
-{
- public class DrawingArea : System.Windows.Controls.Canvas
- {
- public Action resizeCallback;
-
- public Color Color;
- private Brush Brush;
-
- public DrawingArea(Container container) : base()
- {
- this.SizeChanged += UpdateSize;
- ResetGraphics();
-
- container.Add(this, true);
- }
-
- public void UpdateSize(object sender, SizeChangedEventArgs e)
- {
- if(resizeCallback != null)
- {
- Children.Clear();
- ResetGraphics();
-
- Size s = e.NewSize;
- resizeCallback((int)s.Width, (int)s.Height);
- }
- }
-
- public void Redraw()
- {
- if (resizeCallback != null)
- {
- Children.Clear();
- ResetGraphics();
-
- resizeCallback((int)ActualWidth, (int)ActualHeight);
- }
-
- }
-
- private void ResetGraphics()
- {
- Color = Color.FromRgb(0, 0, 0);
- Brush = System.Windows.Media.Brushes.Black;
- }
-
- public void SetColor(int r, int g, int b)
- {
- Color = Color.FromRgb((byte)r, (byte)g, (byte)b);
- Brush = new SolidColorBrush(Color);
- }
-
- public void DrawLine(int x1, int y1, int x2, int y2)
- {
- Line line = new Line();
- line.Stroke = Brush;
- line.StrokeThickness = 1;
- line.SnapsToDevicePixels = true;
-
- line.X1 = x1;
- line.Y1 = y1;
- line.X2 = x2;
- line.Y2 = y2;
-
- Children.Add(line);
- }
-
- public void DrawRect(int x, int y, int w, int h, bool fill)
- {
- Rectangle rect = new Rectangle();
- rect.Stroke = Brush;
- rect.StrokeThickness = 1;
- rect.SnapsToDevicePixels = true;
- if(fill)
- {
- rect.Fill = Brush;
- }
-
- rect.Width = w;
- rect.Height = h;
- SetLeft(rect, x);
- SetTop(rect, y);
-
- Children.Add(rect);
- }
- }
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/MainToolBar.cs
--- a/ui/wpf/UIcore/MainToolBar.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-
-namespace UI
-{
- public class MainToolBar
- {
- Dictionary Items = new Dictionary();
- List Defaults = new List();
-
- public MainToolBar()
- {
-
- }
-
- public bool HasItems()
- {
- return Defaults.Count > 0 ? true : false;
- }
-
- public void AddDefault(string itemName)
- {
- Defaults.Add(itemName);
- }
-
- public void AddToolItem(string name, string label, Action action)
- {
- ToolItem item = new ToolItem();
- item.Label = label;
- item.Action = action;
- Items.Add(name, item);
- }
-
- public ToolBarTray CreateToolBarTray(IntPtr objptr)
- {
- ToolBarTray tray = new ToolBarTray();
- ToolBar toolbar = new ToolBar();
- tray.ToolBars.Add(toolbar);
- foreach(string s in Defaults)
- {
- IToolItem item = Items[s];
- item.AddTo(toolbar, objptr);
- }
-
- return tray;
- }
- }
-
- public interface IToolItem
- {
- void AddTo(System.Windows.Controls.ToolBar toolbar, IntPtr uiobj);
- }
-
- public class ToolItem : IToolItem
- {
- public string Label { get; set; }
- // TODO: icon
- public Action Action { get; set; }
-
- public void AddTo(System.Windows.Controls.ToolBar toolbar, IntPtr uiobj)
- {
- Button button = new Button();
- button.Content = Label;
-
- EventCallback e = new EventCallback(uiobj, Action);
- button.Click += e.Callback;
-
- toolbar.Items.Add(button);
- }
- }
-}
diff -r b34bd1557c6c -r 77254bd6dccb ui/wpf/UIcore/Menu.cs
--- a/ui/wpf/UIcore/Menu.cs Sat Apr 05 17:57:04 2025 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-
-namespace UI
-{
- public class ApplicationMenu
- {
- private List