}
static void toolbar_init(void) {
+ ui_toolbar_item("Back", .icon = UI_ICON_GO_BACK);
+ ui_toolbar_item("Forward", .icon = UI_ICON_GO_FORWARD);
ui_toolbar_item("Home", .icon = UI_ICON_HOME, .onclick = action_go_home);
-
+#ifdef UI_LIBADWAITA
+ ui_toolbar_add_default("Back", UI_TOOLBAR_LEFT);
+ ui_toolbar_add_default("Forward", UI_TOOLBAR_LEFT);
+ ui_toolbar_add_default("Home", UI_TOOLBAR_RIGHT);
+#else
ui_toolbar_add_default("Home", UI_TOOLBAR_LEFT);
+#endif
}
static void appmenu_init(void) {
mz_update_files_view((MzFilesView*)win->files_gridview, sections, numsections);
}
+#ifdef UI_LIBADWAITA
+
+void libadwaita_headerbar_add() {
+
+}
+
+#endif
+
UiObject* window_create(const char *url) {
// toplevel window object
- UiObject *obj = ui_sidebar_window("Mizunara", NULL);
+ UiObject *obj = ui_sidebar_window("Mizunara");
ui_window_size(obj, 1000, 600);
// create window data object
.fill = TRUE);
}
+#ifdef UI_LIBADWAITA
+ ui_headerbar(obj) {
+ ui_headerbar_center(obj) {
+ ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
+ }
+ }
+#else
ui_hbox(obj, .spacing = 4, .margin_left = 6, .margin_right = 8) {
ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_BACK);
ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_FORWARD);
ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
}
+#endif
window_create_browser_view(obj, wdata);
ui_set(browser->view, 0); // select default view
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "app.h"
+
+static ui_callback startup_func;
+static void *startup_data;
+static ui_callback open_func;
+void *open_data;
+static ui_callback exit_func;
+void *exit_data;
+
+
+void ui_onstartup(ui_callback f, void *userdata) {
+ startup_func = f;
+ startup_data = userdata;
+}
+
+void ui_onopen(ui_callback f, void *userdata) {
+ open_func = f;
+ open_data = userdata;
+}
+
+void ui_onexit(ui_callback f, void *userdata) {
+ exit_func = f;
+ exit_data = userdata;
+}
+
+
+void uic_application_startup(UiEvent *event) {
+ if(startup_func) {
+ startup_func(event, startup_data);
+ }
+}
+
+void uic_application_open(UiEvent *event) {
+ if(open_func) {
+ open_func(event, open_data);
+ }
+}
+
+void uic_application_exit(UiEvent *event) {
+ if(exit_func) {
+ exit_func(event, exit_data);
+ }
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_APP_H
+#define UIC_APP_H
+
+#include "../ui/toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uic_application_startup(UiEvent *event);
+void uic_application_open(UiEvent *event);
+void uic_application_exit(UiEvent *event);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_APP_H */
+
free((void*)args->lbutton2);
free((void*)args->rbutton3);
free((void*)args->rbutton4);
- free((void*)args->lbutton1_groups);
- free((void*)args->lbutton2_groups);
- free((void*)args->rbutton3_groups);
- free((void*)args->rbutton4_groups);
+ free((void*)args->lbutton1_states);
+ free((void*)args->lbutton2_states);
+ free((void*)args->rbutton3_states);
+ free((void*)args->rbutton4_states);
free(args);
}
args->onclickdata = onclickdata;
}
-void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_toolbar_item_args_set_states(UiToolbarItemArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_toolbar_item_args_free(UiToolbarItemArgs *args) {
free((void*)args->label);
free((void*)args->icon);
free((void*)args->tooltip);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->onchangedata = onchangedata;
}
-void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args,int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *args,int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
free((void*)args->icon);
free((void*)args->tooltip);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->onclickdata = onclickdata;
}
-void ui_button_args_set_groups(UiButtonArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_button_args_free(UiButtonArgs *args) {
free((void*)args->label);
free((void*)args->icon);
free((void*)args->tooltip);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->value = value;
}
-void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group) {
- args->enable_group = group;
+void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state) {
+ args->enable_state = state;
}
-void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_toggle_args_free(UiToggleArgs *args) {
free((void*)args->icon);
free((void*)args->tooltip);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->value = value;
}
-void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_linkbutton_args_free(UiLinkButtonArgs *args) {
free((void*)args->label);
free((void*)args->uri);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->contextmenu = menubuilder;
}
-void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_list_args_set_states(UiListArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_list_args_free(UiListArgs *args) {
}
free(args->static_elements);
}
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
free((void*)args->style_class);
free((void*)args->varname);
free((void*)args->sublists);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->value = value;
}
-void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_textarea_args_free(UiTextAreaArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->value = value;
}
-void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_textfield_args_free(UiTextFieldArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->rangevalue = value;
}
-void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_spinbox_args_set_states(UiSpinBoxArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_spinbox_args_free(UiSpinBoxArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
args->value = value;
}
-void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates) {
- args->groups = calloc(numstates+1, sizeof(int));
- memcpy((void*)args->groups, states, numstates * sizeof(int));
- ((int*)args->groups)[numstates] = -1;
+void ui_webview_args_set_states(UiWebviewArgs *args, int *states, int numstates) {
+ args->states = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->states, states, numstates * sizeof(int));
+ ((int*)args->states)[numstates] = -1;
}
void ui_webview_args_free(UiWebviewArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
- free((void*)args->groups);
+ free((void*)args->states);
free(args);
}
#include "../ui/entry.h"
#include "../ui/menu.h"
#include "../ui/toolbar.h"
-#include "../ui/tree.h"
+#include "../ui/list.h"
#include "../ui/text.h"
#include "../ui/webview.h"
#include "../ui/widget.h"
UIEXPORT void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip);
UIEXPORT void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback);
UIEXPORT void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata);
-UIEXPORT void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *states, int numstates);
+UIEXPORT void ui_toolbar_item_args_set_states(UiToolbarItemArgs *args, int *states, int numstates);
UIEXPORT void ui_toolbar_item_args_free(UiToolbarItemArgs *args);
UIEXPORT UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void);
UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname);
UIEXPORT void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback);
UIEXPORT void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata);
-UIEXPORT void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *states, int numstates);
+UIEXPORT void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *args, int *states, int numstates);
UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
UIEXPORT void ui_container_args_set_margin_left(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_margin_top(UiContainerArgs *args, int value);
-UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_bottom(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_colspan(UiContainerArgs *args, int colspan);
UIEXPORT void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan);
UIEXPORT void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value);
UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype);
UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback);
UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata);
-UIEXPORT void ui_button_args_set_groups(UiButtonArgs *args, int *states, int numstates);
+UIEXPORT void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates);
UIEXPORT void ui_button_args_free(UiButtonArgs *args);
UIEXPORT UiToggleArgs* ui_toggle_args_new(void);
UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname);
UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value);
-UIEXPORT void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group);
-UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates);
+UIEXPORT void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state);
+UIEXPORT void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int numstates);
UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
UIEXPORT UiLinkButtonArgs* ui_linkbutton_args_new(void);
UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata);
UIEXPORT void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value);
UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type);
-UIEXPORT void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *states, int numstates);
+UIEXPORT void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates);
UIEXPORT void ui_linkbutton_args_free(UiLinkButtonArgs *args);
UIEXPORT UiListArgs* ui_list_args_new(void);
UIEXPORT void ui_list_args_set_onsavedata(UiListArgs *args, void *userdata);
UIEXPORT void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection);
UIEXPORT void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder);
-UIEXPORT void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates);
+UIEXPORT void ui_list_args_set_states(UiListArgs *args, int *states, int numstates);
UIEXPORT void ui_list_args_free(UiListArgs *args);
UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void);
UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname);
UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value);
-UIEXPORT void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *states, int numstates);
+UIEXPORT void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates);
UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args);
UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void);
UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname);
UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value);
-UIEXPORT void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *states, int numstates);
+UIEXPORT void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates);
UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args);
UIEXPORT UiSpinBoxArgs* ui_spinbox_args_new(void);
UIEXPORT void ui_spinbox_args_set_intvalue(UiSpinBoxArgs *args, UiInteger *value);
UIEXPORT void ui_spinbox_args_set_doublevalue(UiSpinBoxArgs *args, UiDouble *value);
UIEXPORT void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value);
-UIEXPORT void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates);
+UIEXPORT void ui_spinbox_args_set_states(UiSpinBoxArgs *args, int *states, int numstates);
UIEXPORT void ui_spinbox_args_free(UiSpinBoxArgs *args);
UIEXPORT UiWebviewArgs* ui_webview_args_new(void);
UIEXPORT void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname);
UIEXPORT void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname);
UIEXPORT void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value);
-UIEXPORT void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates);
+UIEXPORT void ui_webview_args_set_states(UiWebviewArgs *args, int *states, int numstates);
UIEXPORT void ui_webview_args_free(UiWebviewArgs *args);
#ifdef __cplusplus
ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16);
ctx->documents = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, CX_STORE_POINTERS);
- ctx->group_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiGroupWidget));
- ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
+ ctx->state_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiStateWidget));
+ ctx->states = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32);
ctx->attach_document = uic_context_attach_document;
ctx->detach_document2 = uic_context_detach_document;
}
void uic_context_prepare_close(UiContext *ctx) {
- cxListClear(ctx->groups);
- cxListClear(ctx->group_widgets);
+ cxListClear(ctx->states);
+ cxListClear(ctx->state_widgets);
}
void uic_context_attach_document(UiContext *ctx, void *document) {
+ if(ctx->single_document_mode) {
+ if(ctx->document) {
+ uic_context_detach_document(ctx, ctx->document);
+ }
+ }
+
cxListAdd(ctx->documents, document);
ctx->document = document;
UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
if(docvar) {
// bind var to document var
- uic_copy_binding(var, docvar, TRUE);
+ uic_copy_var_binding(var, docvar, TRUE);
cxIteratorFlagRemoval(i);
}
}
}
static void uic_context_unbind_vars(UiContext *ctx) {
+ ui_onchange_events_enable(FALSE);
CxMapIterator mi = cxMapIterator(ctx->vars);
cx_foreach(CxMapEntry*, entry, mi) {
+ printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
UiVar *var = entry->value;
// var->from && var->from_ctx && var->from_ctx != ctx
uic_save_var(var);
if(var->from) {
- uic_copy_binding(var, var->from, FALSE);
+ uic_copy_var_binding(var, var->from, FALSE);
cxMapPut(var->from->from_ctx->vars, *entry->key, var->from);
var->from = NULL;
}
+ uic_unbind_var(var);
}
if(ctx->documents) {
uic_context_unbind_vars(subctx);
}
}
+
+ ui_onchange_events_enable(TRUE);
}
void uic_context_detach_document(UiContext *ctx, void *document) {
return ctx_getvar(ctx, key);
}
+UiVar* uic_get_var_t(UiContext *ctx,const char *name, UiVarType type) {
+ UiVar *var = uic_get_var(ctx, name);
+ if(var && var->type == type) {
+ return var;
+ }
+ return NULL;
+}
+
UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
UiVar *var = uic_get_var(ctx, name);
if(var) {
var->original_value = NULL;
var->from = NULL;
var->from_ctx = ctx;
-
- cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var);
+ var->bound = FALSE;
+
+ cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var); // TODO: use another destructor that cleans the value (UiString free, UiText destroy, ...)
cxMapPut(ctx->vars, name, var);
return val;
}
+// destroys a value, that was created by uic_create_value
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value) {
+ switch(type) {
+ default: {
+ ui_free(ctx, value);
+ break;
+ }
+ case UI_VAR_SPECIAL: break;
+ case UI_VAR_STRING: {
+ UiString *s = value;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ ui_free(ctx, value);
+ }
+ case UI_VAR_TEXT: {
+ UiText *t = value;
+ if(t->value.free) {
+ t->value.free(t->value.ptr);
+ t->value.free = NULL;
+ t->value.ptr = NULL;
+ }
+ if(t->destroy) {
+ t->destroy(t);
+ }
+ ui_free(ctx, value);
+ }
+ case UI_VAR_LIST: {
+ ui_list_free(ctx, value);
+ break;
+ }
+ }
+}
+
UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) {
if (value) {
}
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
// check type
if(from->type != to->type) {
fprintf(stderr, "UI Error: var has incompatible type.\n");
}
}
- ui_setop_enable(TRUE);
+ uic_copy_value_binding(from->type, fromvalue, tovalue);
+}
+
+void uic_copy_value_binding(UiVarType type, void *from, void *to) {
+ ui_setop_enable(TRUE);
// copy binding
- // we don't copy the observer, because the from var has never one
- switch(from->type) {
+ // we don't copy the observer, because the from value never has oberservers
+ switch(type) {
default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break;
case UI_VAR_SPECIAL: break;
case UI_VAR_INTEGER: {
- UiInteger *f = fromvalue;
- UiInteger *t = tovalue;
+ UiInteger *f = from;
+ UiInteger *t = to;
if(!f->obj) break;
uic_int_copy(f, t);
t->set(t, t->value);
break;
}
case UI_VAR_DOUBLE: {
- UiDouble *f = fromvalue;
- UiDouble *t = tovalue;
+ UiDouble *f = from;
+ UiDouble *t = to;
if(!f->obj) break;
uic_double_copy(f, t);
t->set(t, t->value);
break;
}
case UI_VAR_STRING: {
- UiString *f = fromvalue;
- UiString *t = tovalue;
+ UiString *f = from;
+ UiString *t = to;
if(!f->obj) break;
uic_string_copy(f, t);
char *tvalue = t->value.ptr ? t->value.ptr : "";
break;
}
case UI_VAR_TEXT: {
- UiText *f = fromvalue;
- UiText *t = tovalue;
+ UiText *f = from;
+ UiText *t = to;
if(!f->obj) break;
uic_text_copy(f, t);
t->restore(t);
break;
}
case UI_VAR_LIST: {
- UiList *f = fromvalue;
- UiList *t = tovalue;
+ UiList *f = from;
+ UiList *t = to;
uic_list_copy(f, t);
ui_list_update(t);
break;
}
case UI_VAR_RANGE: {
- UiRange *f = fromvalue;
- UiRange *t = tovalue;
+ UiRange *f = from;
+ UiRange *t = to;
if(!f->obj) break;
uic_range_copy(f, t);
t->setextent(t, t->extent);
break;
}
case UI_VAR_GENERIC: {
- UiGeneric *f = fromvalue;
- UiGeneric *t = tovalue;
+ UiGeneric *f = from;
+ UiGeneric *t = to;
if(!f->obj) break;
uic_generic_copy(f, t);
t->set(t, t->value, t->type);
}
}
+const char *uic_type2str(UiVarType type) {
+ switch(type) {
+ default: return "";
+ case UI_VAR_INTEGER: return "int";
+ case UI_VAR_DOUBLE: return "double";
+ case UI_VAR_STRING: return "string";
+ case UI_VAR_TEXT: return "text";
+ case UI_VAR_LIST: return "list";
+ case UI_VAR_RANGE: return "range";
+ case UI_VAR_GENERIC: return "generic";
+ }
+}
+
void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) {
- // TODO: do we need/want this? Why adding vars to a context after
- // widgets reference these? Workarounds:
- // 1. add vars to ctx before creating ui
- // 2. create ui, create new document with vars, attach doc
- // also it would be possible to create a function, that scans unbound vars
- // and connects them to available vars
- /*
- UiContext *rootctx = uic_root_context(ctx);
- UiVar *b = NULL;
- if(rootctx->bound) {
- // some widgets are already bound to some vars
- b = ucx_map_cstr_get(rootctx->bound, name);
- if(b) {
- // a widget is bound to a var with this name
- // if ctx is the root context we can remove the var from bound
- // because set_doc or detach can't fuck things up
- if(ctx == rootctx) {
- ucx_map_cstr_remove(ctx->bound, name);
- // TODO: free stuff
- }
+ UiVar *var = cxMapGet(ctx->vars, name);
+ if(!var) {
+ // create new var and add it to the context var map
+ var = ui_malloc(ctx, sizeof(UiVar));
+ cxMapPut(ctx->vars, name, var);
+ } else {
+ // override var with new value
+ if(var->type != type) {
+ fprintf(stderr, "Error: var %s type mismatch: %s - %s\n", name, uic_type2str(var->type), uic_type2str(type));
+ return;
+ }
+ if(var->bound) {
+ fprintf(stderr, "Error: var %s already bound\n", name);
+ return;
}
+ UiInteger *prev_value = var->value;
+ uic_copy_value_binding(type, prev_value, value);
+ uic_destroy_value(var->from_ctx, var->type, var->value);
}
- */
- // create new var and add it to doc's vars
- UiVar *var = ui_malloc(ctx, sizeof(UiVar));
var->type = type;
var->value = value;
var->from = NULL;
var->from_ctx = ctx;
- size_t oldcount = cxMapSize(ctx->vars);
- cxMapPut(ctx->vars, name, var);
- if(cxMapSize(ctx->vars) != oldcount + 1) {
- fprintf(stderr, "UiError: var '%s' already exists\n", name);
- }
-
- // TODO: remove?
- // a widget is already bound to a var with this name
- // copy the binding (like uic_context_set_document)
- /*
- if(b) {
- uic_copy_binding(b, var, TRUE);
- }
- */
+ var->bound = TRUE;
}
-void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
- // TODO
-}
+// public API
+void* ui_context_get_document(UiContext *ctx) {
+ return ctx->document;
+}
-// public API
+void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable) {
+ ctx->single_document_mode = enable;
+}
void ui_attach_document(UiContext *ctx, void *document) {
uic_context_attach_document(ctx, document);
}
-void ui_set_group(UiContext *ctx, int group) {
- if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) {
- cxListAdd(ctx->groups, &group);
+void ui_set_state(UiContext *ctx, int state) {
+ if(!cxListIndexValid(ctx->states, cxListFind(ctx->states, &state))) {
+ cxListAdd(ctx->states, &state);
}
// enable/disable group widgets
- uic_check_group_widgets(ctx);
+ uic_check_state_widgets(ctx);
}
-void ui_unset_group(UiContext *ctx, int group) {
- int i = cxListFind(ctx->groups, &group);
+void ui_unset_state(UiContext *ctx, int state) {
+ int i = cxListFind(ctx->states, &state);
if(i != -1) {
- cxListRemove(ctx->groups, i);
+ cxListRemove(ctx->states, i);
}
// enable/disable group widgets
- uic_check_group_widgets(ctx);
+ uic_check_state_widgets(ctx);
}
-int* ui_active_groups(UiContext *ctx, int *ngroups) {
- *ngroups = cxListSize(ctx->groups);
- return cxListAt(ctx->groups, 0);
+int* ui_active_states(UiContext *ctx, int *nstates) {
+ *nstates = cxListSize(ctx->states);
+ return cxListAt(ctx->states, 0);
}
-void uic_check_group_widgets(UiContext *ctx) {
+void uic_check_state_widgets(UiContext *ctx) {
int ngroups = 0;
- int *groups = ui_active_groups(ctx, &ngroups);
+ int *groups = ui_active_states(ctx, &ngroups);
- CxIterator i = cxListIterator(ctx->group_widgets);
- cx_foreach(UiGroupWidget *, gw, i) {
- char *check = calloc(1, gw->numgroups);
+ CxIterator i = cxListIterator(ctx->state_widgets);
+ cx_foreach(UiStateWidget *, gw, i) {
+ char *check = calloc(1, gw->numstates);
for(int i=0;i<ngroups;i++) {
- for(int k=0;k<gw->numgroups;k++) {
- if(groups[i] == gw->groups[k]) {
+ for(int k=0;k<gw->numstates;k++) {
+ if(groups[i] == gw->states[k]) {
check[k] = 1;
}
}
}
int enable = 1;
- for(int i=0;i<gw->numgroups;i++) {
+ for(int i=0;i<gw->numstates;i++) {
if(check[i] == 0) {
enable = 0;
break;
}
}
-void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
+void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
if(enable == NULL) {
enable = (ui_enablefunc)ui_set_enabled;
}
- // get groups
- CxList *groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
+ // get states
+ CxList *states = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
va_list ap;
va_start(ap, enable);
- int group;
- while((group = va_arg(ap, int)) != -1) {
- cxListAdd(groups, &group);
+ int state;
+ while((state = va_arg(ap, int)) != -1) {
+ cxListAdd(states, &state);
}
va_end(ap);
- uic_add_group_widget(ctx, widget, enable, groups);
+ uic_add_state_widget(ctx, widget, enable, states);
- cxListFree(groups);
+ cxListFree(states);
}
-void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups) {
+void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates) {
if(enable == NULL) {
enable = (ui_enablefunc)ui_set_enabled;
}
- CxList *ls = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), ngroups);
- for(int i=0;i<ngroups;i++) {
- cxListAdd(ls, groups+i);
+ CxList *ls = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), nstates);
+ for(int i=0;i<nstates;i++) {
+ cxListAdd(ls, states+i);
}
- uic_add_group_widget(ctx, widget, enable, ls);
+ uic_add_state_widget(ctx, widget, enable, ls);
cxListFree(ls);
}
void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates) {
- ui_widget_set_groups2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates);
+ ui_widget_set_states2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates);
}
-size_t uic_group_array_size(const int *groups) {
+size_t uic_state_array_size(const int *states) {
int i;
- for(i=0;groups[i] >= 0;i++) { }
+ for(i=0;states[i] >= 0;i++) { }
return i;
}
-void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups) {
- uic_add_group_widget_i(ctx, widget, enable, cxListAt(groups, 0), cxListSize(groups));
+void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *states) {
+ uic_add_state_widget_i(ctx, widget, enable, cxListAt(states, 0), cxListSize(states));
}
-void uic_add_group_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *groups, size_t numgroups) {
+void uic_add_state_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *states, size_t numstates) {
const CxAllocator *a = ctx->allocator;
- UiGroupWidget gw;
+ UiStateWidget gw;
gw.widget = widget;
gw.enable = enable;
- gw.numgroups = numgroups;
- gw.groups = cxCalloc(a, numgroups, sizeof(int));
+ gw.numstates = numstates;
+ gw.states = cxCalloc(a, numstates, sizeof(int));
- // copy groups
- if(groups) {
- memcpy(gw.groups, groups, gw.numgroups * sizeof(int));
+ // copy states
+ if(states) {
+ memcpy(gw.states, states, gw.numstates * sizeof(int));
}
- cxListAdd(ctx->group_widgets, &gw);
+ cxListAdd(ctx->state_widgets, &gw);
}
-void uic_remove_group_widget(UiContext *ctx, void *widget) {
- (void)cxListFindRemove(ctx->group_widgets, widget);
+void uic_remove_state_widget(UiContext *ctx, void *widget) {
+ (void)cxListFindRemove(ctx->state_widgets, widget);
}
UIEXPORT void *ui_allocator(UiContext *ctx) {
void ui_set_destructor(void *mem, ui_destructor_func destr) {
cxMempoolSetDestructor(mem, (cx_destructor_func)destr);
}
+
+UiInteger* ui_get_int_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_INTEGER);
+ return var ? var->value : NULL;
+}
+
+UiDouble* ui_get_double_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_DOUBLE);
+ return var ? var->value : NULL;
+}
+
+UiString* ui_get_string_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_STRING);
+ return var ? var->value : NULL;
+}
+
+UiText* ui_get_text_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_TEXT);
+ return var ? var->value : NULL;
+}
+
+UiRange* ui_get_range_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_RANGE);
+ return var ? var->value : NULL;
+}
+
+UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name) {
+ UiVar *var = uic_get_var_t(ctx, name, UI_VAR_GENERIC);
+ return var ? var->value : NULL;
+}
typedef struct UiVar UiVar;
typedef struct UiListPtr UiListPtr;
typedef struct UiListVar UiListVar;
-typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiStateWidget UiStateWidget;
typedef struct UiDestroyHandler UiDestroyHandler;
typedef enum UiVarType {
CxMap *vars;
- CxList *groups; // int list
- CxList *group_widgets; // UiGroupWidget list
+ CxList *states; // int list
+ CxList *state_widgets; // UiGroupWidget list
void (*attach_document)(UiContext *ctx, void *document);
void (*detach_document2)(UiContext *ctx, void *document);
GtkAccelGroup *accel_group;
#endif
#endif
-
-
+
+ // allow only one document to be attached
+ // attaching a document will automatically detach the current document
+ UiBool single_document_mode;
ui_callback close_callback;
void *close_data;
UiVarType type;
UiVar *from;
UiContext *from_ctx;
+ UiBool bound;
};
-struct UiGroupWidget {
+struct UiStateWidget {
void *widget;
ui_enablefunc enable;
- int *groups;
- int numgroups;
+ int *states;
+ int numstates;
};
struct UiDestroyHandler {
void uic_context_detach_all(UiContext *ctx);
UiVar* uic_get_var(UiContext *ctx, const char *name);
+UiVar* uic_get_var_t(UiContext *ctx, const char *name, UiVarType type);
UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type);
UiVar* uic_create_value_var(UiContext *ctx, void *value);
void* uic_create_value(UiContext *ctx, UiVarType type);
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value);
UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type);
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_value_binding(UiVarType type, void *from, void *to);
void uic_save_var(UiVar *var);
void uic_unbind_var(UiVar *var);
+const char *uic_type2str(UiVarType type);
void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
-void uic_remove_bound_var(UiContext *ctx, UiVar *var);
-
-size_t uic_group_array_size(const int *groups);
-void uic_check_group_widgets(UiContext *ctx);
-void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups);
-void uic_add_group_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *groups, size_t numgroups);
-void uic_remove_group_widget(UiContext *ctx, void *widget);
+size_t uic_state_array_size(const int *states);
+void uic_check_state_widgets(UiContext *ctx);
+void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *states);
+void uic_add_state_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *states, size_t numstates);
+void uic_remove_state_widget(UiContext *ctx, void *widget);
#ifdef __cplusplus
}
return s ? strdup(s) : NULL;
}
-int* uic_copy_groups(const int* groups, size_t *ngroups) {
- *ngroups = 0;
- if (!groups) {
+int* uic_copy_states(const int* states, size_t *nstates) {
+ *nstates = 0;
+ if (!states) {
return NULL;
}
size_t n;
- for (n = 0; groups[n] > -1; n++) { }
+ for (n = 0; states[n] > -1; n++) { }
- if (ngroups > 0) {
+ if (nstates > 0) {
int* newarray = calloc(n+1, sizeof(int));
- memcpy(newarray, groups, n * sizeof(int));
+ memcpy(newarray, states, n * sizeof(int));
newarray[n] = -1;
- *ngroups = n;
+ *nstates = n;
return newarray;
}
return NULL;
item->icon = nl_strdup(args->icon);
item->userdata = args->onclickdata;
item->callback = args->onclick;
- item->groups = uic_copy_groups(args->groups, &item->ngroups);
+ item->states = uic_copy_states(args->states, &item->nstates);
add_item((UiMenuItemI*)item);
}
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
item->callback = args->onchange;
- item->groups = uic_copy_groups(args->groups, &item->ngroups);
+ item->states = uic_copy_states(args->nstates, &item->nstates);
add_item((UiMenuItemI*)item);
}
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
item->callback = args->onchange;
- item->groups = uic_copy_groups(args->groups, &item->ngroups);
+ item->states = uic_copy_states(args->nstates, &item->nstates);
add_item((UiMenuItemI*)item);
}
}
case UI_MENU_ITEM: {
UiMenuItem *i = (UiMenuItem*)item;
- free(i->groups);
+ free(i->states);
free(i->label);
free(i->icon);
break;
}
case UI_MENU_CHECK_ITEM: {
UiMenuCheckItem *i = (UiMenuCheckItem*)item;
- free(i->groups);
+ free(i->states);
free(i->label);
free(i->icon);
free(i->varname);
}
case UI_MENU_RADIO_ITEM: {
UiMenuRadioItem *i = (UiMenuRadioItem*)item;
- free(i->groups);
+ free(i->states);
free(i->label);
free(i->icon);
free(i->varname);
char *label;
char *icon;
void *userdata;
- int *groups;
- size_t ngroups;
+ int *states;
+ size_t nstates;
};
struct UiMenuCheckItem {
char *varname;
ui_callback callback;
void *userdata;
- int *groups;
- size_t ngroups;
+ int *states;
+ size_t nstates;
};
struct UiMenuRadioItem {
char *varname;
ui_callback callback;
void *userdata;
- int *groups;
- size_t ngroups;
+ int *states;
+ size_t nstates;
};
struct UiMenuItemList {
void uic_add_menu_to_stack(UiMenu* menu);
-int* uic_copy_groups(const int* groups, size_t *ngroups);
+int* uic_copy_states(const int* states, size_t *nstates);
void uic_set_tmp_eventdata(void *eventdata, int type);
void* uic_get_tmp_eventdata(void);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _WIN32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "message.h"
+
+int uic_message_send_(UiMessageHandler *handler, cxstring msg) {
+ return handler->send(handler, msg);
+}
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback) {
+ UiSimpleMessageHandler *handler = malloc(sizeof(UiSimpleMessageHandler));
+ handler->handler.start = uic_simple_msg_handler_start;
+ handler->handler.stop = uic_simple_msg_handler_stop;
+ handler->handler.send = uic_simple_msg_handler_send;
+ handler->handler.callback = callback;
+ handler->in = in;
+ handler->out = out;
+ handler->outbuf = cxBufferCreate(NULL, 4096, NULL, CX_BUFFER_FREE_CONTENTS | CX_BUFFER_AUTO_EXTEND);
+ handler->stop = 0;
+ pthread_mutex_init(&handler->queue_lock, NULL);
+ pthread_mutex_init(&handler->avlbl_lock, NULL);
+ pthread_cond_init(&handler->available, NULL);
+ return (UiMessageHandler*)handler;
+}
+
+int uic_simple_msg_handler_start(UiMessageHandler *handler) {
+ UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+ if(pthread_create(&sh->in_thread, NULL, uic_simple_msg_handler_in_thread, sh)) {
+ return 1;
+ }
+ if(pthread_create(&sh->out_thread, NULL, uic_simple_msg_handler_out_thread, sh)) {
+ return 1;
+ }
+ return 0;
+}
+
+int uic_simple_msg_handler_stop(UiMessageHandler *handler) {
+ UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+ pthread_mutex_lock(&sh->queue_lock);
+ sh->stop = 0;
+ pthread_cond_signal(&sh->available);
+ pthread_mutex_unlock(&sh->queue_lock);
+ close(sh->in);
+ sh->in = -1;
+
+ pthread_join(sh->in_thread, NULL);
+ pthread_join(sh->out_thread, NULL);
+
+ return 0;
+}
+
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg) {
+ UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+ pthread_mutex_lock(&sh->queue_lock);
+ char header[32];
+ snprintf(header, 32, "%zu\n", msg.length);
+ cxBufferPutString(sh->outbuf, header);
+ cxBufferWrite(msg.ptr, 1, msg.length, sh->outbuf);
+ pthread_cond_signal(&sh->available);
+ pthread_mutex_unlock(&sh->queue_lock);
+ return 0;
+}
+
+#define HEADERBUF_SIZE 64
+
+void* uic_simple_msg_handler_in_thread(void *data) {
+ UiSimpleMessageHandler *handler = data;
+
+ char *msg = NULL;
+ size_t msg_size = 0;
+ size_t msg_pos = 0; // currently received message length
+
+ char headerbuf[HEADERBUF_SIZE];
+ size_t headerpos = 0;
+
+ char buf[2048];
+ ssize_t r;
+ while((r = read(handler->in, buf, 2024)) > 0) {
+ char *buffer = buf;
+ size_t available = r;
+
+ while(available > 0) {
+ if(msg) {
+ // read message
+ size_t need = msg_size - msg_pos;
+ size_t cplen = r > need ? need : available;
+ memcpy(msg+msg_pos, buffer, cplen);
+ buffer += cplen;
+ available -= cplen;
+ msg_pos += cplen;
+ if(msg_pos == msg_size) {
+ // message complete
+ //fprintf(stderr, "send: %.*s\n", (int)msg_size, msg);
+ if(handler->handler.callback) {
+ handler->handler.callback(cx_strn(msg, msg_size));
+ }
+ free(msg);
+ msg = NULL;
+ msg_size = 0;
+ msg_pos = 0;
+ }
+ } else {
+ size_t header_max = HEADERBUF_SIZE - headerpos - 1;
+ if(header_max > available) {
+ header_max = available;
+ }
+ // search for line break
+ int i;
+ int header_complete = 0;
+ for(i=0;i<header_max;i++) {
+ if(buffer[i] == '\n') {
+ header_complete = 1;
+ break;
+ }
+ }
+ i++;
+ memcpy(headerbuf+headerpos, buffer, i);
+ headerpos += i;
+ buffer += i;
+ available -= i;
+
+ if(header_complete) {
+ headerbuf[headerpos-1] = 0; // terminate buffer
+ char *end;
+ long length = strtol(headerbuf, &end, 10);
+ if(*end == '\0') {
+ //fprintf(stderr, "header: %d\n", (int)length);
+ msg = malloc(length);
+ msg_size = length;
+ headerpos = 0;
+ } else {
+ fprintf(stderr, "Error: invalid message {%s}\n", headerbuf);
+ }
+ } else if(headerpos+1 >= HEADERBUF_SIZE) {
+ fprintf(stderr, "Error: message header too big\n");
+ exit(-1);
+ }
+ }
+ }
+
+
+ }
+ perror("error");
+ fprintf(stderr, "stop simple_msg_handler_in_thread\n");
+
+ return NULL;
+}
+
+void* uic_simple_msg_handler_out_thread(void *data) {
+ UiSimpleMessageHandler *handler = data;
+ CxBuffer *buffer = handler->outbuf;
+
+ pthread_mutex_lock(&handler->queue_lock);
+
+ for(;;) {
+ if(buffer->pos == 0) {
+ pthread_cond_wait(&handler->available, &handler->queue_lock);
+ continue;
+ } else {
+ size_t n = buffer->pos;
+ size_t pos = 0;
+ while(n > 0) {
+ ssize_t w = write(handler->out, buffer->space + pos, n);
+ if(w <= 0) {
+ fprintf(stderr, "Error: output error\n");
+ break;
+ }
+ n -= w;
+ pos += w;
+ }
+ if(n > 0) {
+ break; // error
+ }
+ buffer->pos = 0;
+ }
+ }
+
+ pthread_mutex_unlock(&handler->queue_lock);
+
+ return NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_MESSAGE_H
+#define UIC_MESSAGE_H
+
+
+#include <cx/string.h>
+#include <cx/json.h>
+#include <cx/buffer.h>
+
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct UiMessageHandler UiMessageHandler;
+
+typedef void(*msg_received_callback)(cxstring msg);
+
+struct UiMessageHandler {
+ int (*start)(UiMessageHandler *handler);
+ int (*stop)(UiMessageHandler *handler);
+ int (*send)(UiMessageHandler *handler, cxstring msg);
+
+ msg_received_callback callback;
+};
+
+typedef struct UiSimpleMessageHandler {
+ UiMessageHandler handler;
+ int in;
+ int out;
+#ifndef _WIN32
+ pthread_t in_thread;
+ pthread_t out_thread;
+ pthread_mutex_t queue_lock;
+ pthread_mutex_t avlbl_lock;
+ pthread_cond_t available;
+#endif
+ CxBuffer *outbuf;
+ int stop;
+} UiSimpleMessageHandler;
+
+int uic_message_send_(UiMessageHandler *handler, cxstring msg);
+#define uic_message_send(handler, msg) uic_message_send_(handler, cx_strcast(msg))
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback);
+int uic_simple_msg_handler_start(UiMessageHandler *handler);
+int uic_simple_msg_handler_stop(UiMessageHandler *handler);
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg);
+
+void* uic_simple_msg_handler_in_thread(void *data);
+void* uic_simple_msg_handler_out_thread(void *data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_MESSAGE_H */
+
#include "context.h"
#include <cx/linked_list.h>
+#include <cx/hash_map.h>
#include "../ui/container.h"
UiObject* uic_object_new_toplevel(void) {
fflush(stdout);
CxMempool *mp = cxMempoolCreateSimple(256);
- UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+ UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate));
fflush(stdout);
obj->ctx = uic_context(obj, mp);
obj->ctx->parent = ui_global_context();
}
UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
- UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
+ UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObjectPrivate));
newobj->ctx = ctx;
newobj->widget = widget;
uic_object_created(newobj);
fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
}
}
+
+// public API
+
+void ui_object_set(UiObject *obj, const char *key, void *data) {
+ UiObjectPrivate *p = (UiObjectPrivate*)obj;
+ if(!p->ext) {
+ p->ext = cxHashMapCreate(obj->ctx->mp->allocator, CX_STORE_POINTERS, 4);
+ }
+ if(data) {
+ cxMapPut(p->ext, key, data);
+ } else {
+ cxMapRemove(p->ext, key);
+ }
+}
+
+void* ui_object_get(UiObject *obj, const char *key) {
+ UiObjectPrivate *p = (UiObjectPrivate*)obj;
+ return p->ext ? cxMapGet(p->ext, key) : NULL;
+}
#define UIC_OBJECT_H
#include "../ui/toolkit.h"
+#include <cx/map.h>
#ifdef __cplusplus
extern "C" {
#endif
+
+typedef struct UiObjectPrivate {
+ UiObject obj;
+ CxMap *ext;
+} UiObjectPrivate;
typedef void (*ui_object_callback)(UiObject *obj, void *userdata);
COMMON_OBJ += object$(OBJ_EXT)
COMMON_OBJ += container$(OBJ_EXT)
COMMON_OBJ += types$(OBJ_EXT)
+COMMON_OBJ += app$(OBJ_EXT)
COMMON_OBJ += properties$(OBJ_EXT)
COMMON_OBJ += menu$(OBJ_EXT)
COMMON_OBJ += toolbar$(OBJ_EXT)
COMMON_OBJ += condvar$(OBJ_EXT)
COMMON_OBJ += args$(OBJ_EXT)
COMMON_OBJ += wrapper$(OBJ_EXT)
+COMMON_OBJ += utils$(OBJ_EXT)
+COMMON_OBJ += message$(OBJ_EXT)
TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
static char *locales_dir;
static char *pixmaps_dir;
+static UiBool use_xdg_config_home = TRUE;
+
#endif
#define UI_ENV_HOME "USERPROFILE"
#endif
+#define UI_XDG_CONFIG_HOME_VAR "XDG_CONFIG_HOME"
+
char* ui_configfile(const char *name) {
const char *appname = ui_appname();
if(!appname) {
// on Windows the app dir is $USERPROFILE/AppData/Local/$APPNAME/
cxBufferPutString(&buf, "AppData\\Local\\");
#else
- // app dir is $HOME/.$APPNAME/
- cxBufferPut(&buf, '.');
+ if(use_xdg_config_home) {
+ // app dir is $HOME/.config/$APPNAME/
+ char *xdghome = getenv(UI_XDG_CONFIG_HOME_VAR);
+ size_t xdghomelen = xdghome ? strlen(xdghome) : 0;
+ if(xdghome && xdghomelen > 0) {
+ cxBufferSeek(&buf, 0, SEEK_SET);
+ cxBufferPutString(&buf, xdghome);
+ if(xdghome[xdghomelen-1] != '/') {
+ cxBufferPut(&buf, '/');
+ }
+ } else {
+ cxBufferPutString(&buf, ".config/");
+ }
+ } else {
+ cxBufferPut(&buf, '.');
+ }
+
#endif
cxBufferPutString(&buf, appname);
cxBufferPut(&buf, UI_PATH_SEPARATOR);
if(!dir) {
return;
}
+ size_t len = strlen(dir);
+ if(len < 2) {
+ return;
+ }
if(ui_mkdir(dir)) {
+ if(errno == ENOENT) {
+ char *parent = strdup(dir);
+ for(int i=len-2;i>=0;i--) {
+ if(parent[i] == '/') {
+ parent[i] = 0;
+ break;
+ }
+ }
+ // try creating the parent
+ int err = ui_mkdir(parent);
+ if(err) {
+ fprintf(stderr, "Error: Cannot create directory %s: %s\n", strerror(errno));
+ free(parent);
+ free(dir);
+ return;
+ }
+ free(parent);
+
+ // try dir again
+ if(!ui_mkdir(dir)) {
+ errno = EEXIST; // success
+ }
+ }
+
if(errno != EEXIST) {
- fprintf(stderr, "Ui Error: Cannot create directory %s\n", dir);
+ fprintf(stderr, "Error: Cannot create directory %s: %s\n", dir, strerror(errno));
free(dir);
return;
}
UiThreadpool* threadpool_new(int min, int max) {
UiThreadpool *pool = malloc(sizeof(UiThreadpool));
- pool->queue = NULL;
- pool->queue_len = 0;
+ pool->queue = ui_queue_create();
pool->num_idle = 0;
pool->min_threads = min;
pool->max_threads = max;
- pthread_mutex_init(&pool->queue_lock, NULL);
- pthread_mutex_init(&pool->avlbl_lock, NULL);
- pthread_cond_init(&pool->available, NULL);
-
return pool;
}
int threadpool_start(UiThreadpool *pool) {
+ pool->nthreads = pool->min_threads;
+ pool->threads = calloc(pool->max_threads, sizeof(pthread_t));
/* create pool threads */
- for(int i=0;i<pool->min_threads;i++) {
- pthread_t t;
- if (pthread_create(&t, NULL, threadpool_func, pool) != 0) {
+ for(int i=0;i<pool->nthreads;i++) {
+ if (pthread_create(&pool->threads[i], NULL, threadpool_func, pool) != 0) {
fprintf(stderr, "uic: threadpool_start: pthread_create failed: %s", strerror(errno));
return 1;
}
return 0;
}
+int threadpool_join(UiThreadpool *pool) {
+ int err = 0;
+ for(int i=0;i<pool->nthreads;i++) {
+ if(pthread_join(pool->threads[i], NULL)) {
+ err = 1;
+ }
+ }
+ return err;
+}
+
void* threadpool_func(void *data) {
UiThreadpool *pool = (UiThreadpool*)data;
}
threadpool_job* threadpool_get_job(UiThreadpool *pool) {
- pthread_mutex_lock(&pool->queue_lock);
-
- threadpool_job *job = NULL;
- pool->num_idle++;
- while(job == NULL) {
- if(pool->queue_len == 0) {
- pthread_cond_wait(&pool->available, &pool->queue_lock);
- continue;
- } else {
- pool_queue_t *q = pool->queue;
- job = q->job;
- pool->queue = q->next;
- pool->queue_len--;
- free(q);
- }
- }
- pool->num_idle--;
-
- pthread_mutex_unlock(&pool->queue_lock);
+ threadpool_job *job = ui_queue_get_wait(pool->queue);
return job;
}
-void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) {
- // TODO: handle errors
-
+void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) {
threadpool_job *job = malloc(sizeof(threadpool_job));
job->callback = func;
job->data = data;
-
- pthread_mutex_lock(&pool->queue_lock);
- threadpool_enqueue_job(pool, job);
-
- int create_thread = 0;
- int destroy_thread = 0;
- int diff = pool->queue_len - pool->num_idle;
-
- //if(pool->queue_len == 1) {
- pthread_cond_signal(&pool->available);
- //}
-
- pthread_mutex_unlock(&pool->queue_lock);
-}
-
-void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) {
- pool_queue_t *q = malloc(sizeof(pool_queue_t));
- q->job = job;
- q->next = NULL;
-
- if(pool->queue == NULL) {
- pool->queue = q;
- } else {
- pool_queue_t *last_elem = pool->queue;
- while(last_elem->next != NULL) {
- last_elem = last_elem->next;
- }
- last_elem->next = q;
- }
- pool->queue_len++;
+ ui_queue_put(pool->queue, job);
}
-
-
-
UiThreadpool* ui_threadpool_create(int nthreads) {
UiThreadpool *pool = threadpool_new(nthreads, nthreads);
threadpool_start(pool); // TODO: check return value
threadpool_run(pool, ui_threadpool_job_func, job);
}
+/* --------------------------------- Queue --------------------------------- */
+
+UiQueue* ui_queue_create(void) {
+ UiQueue *queue = calloc(1, sizeof(UiQueue));
+ pthread_mutex_init(&queue->lock, NULL);
+ pthread_mutex_init(&queue->avlbl_lock, NULL);
+ pthread_cond_init(&queue->available, NULL);
+ return queue;
+}
+
+void ui_queue_free(UiQueue *queue) {
+ // The queue must be empty, we could free UiQueueElm,
+ // but not the payload data
+ pthread_mutex_destroy(&queue->lock);
+ pthread_mutex_destroy(&queue->avlbl_lock);
+ pthread_cond_destroy(&queue->available);
+ free(queue);
+}
+
+void ui_queue_put(UiQueue *queue, void *data) {
+ // create queue element
+ UiQueueElm *elm = malloc(sizeof(UiQueueElm));
+ elm->data = data;
+ elm->next = NULL;
+
+ pthread_mutex_lock(&queue->lock);
+
+ // put queue element at the end of the linked list
+ if(queue->elements) {
+ UiQueueElm *end = queue->elements;
+ while(end->next) {
+ end = end->next;
+ }
+ end->next = elm;
+ } else {
+ queue->elements = elm;
+ }
+ queue->length++;
+
+ // signal new available data
+ pthread_cond_signal(&queue->available);
+
+ pthread_mutex_unlock(&queue->lock);
+}
+
+void* ui_queue_get_wait(UiQueue *queue) {
+ pthread_mutex_lock(&queue->lock);
+
+ void *data = NULL;
+ while(data == NULL) {
+ if(queue->length == 0) {
+ pthread_cond_wait(&queue->available, &queue->lock);
+ continue;
+ } else {
+ UiQueueElm *q = queue->elements;
+ data = q->data;
+ queue->elements = q->next;
+ queue->length--;
+ free(q);
+ }
+ }
+
+ pthread_mutex_unlock(&queue->lock);
+ return data;
+}
#endif
extern "C" {
#endif
+typedef struct UiQueueElm UiQueueElm;
+typedef struct UiQueue UiQueue;
typedef struct UiJob {
UiObject *obj;
void *finish_data;
} UiJob;
+struct UiQueueElm {
+ void *data;
+ UiQueueElm *next;
+};
+
+struct UiQueue {
+ UiQueueElm *elements;
+ size_t length;
+ pthread_mutex_t lock;
+ pthread_mutex_t avlbl_lock;
+ pthread_cond_t available;
+};
typedef struct _threadpool_job threadpool_job;
typedef void*(*job_callback_f)(void *data);
typedef struct _pool_queue pool_queue_t;
struct UiThreadpool {
- pthread_mutex_t queue_lock;
- pthread_mutex_t avlbl_lock;
- pthread_cond_t available;
- pool_queue_t *queue;
- uint32_t queue_len;
- uint32_t num_idle;
- int min_threads;
- int max_threads;
+ UiQueue *queue;
+ uint32_t num_idle;
+ int min_threads;
+ int max_threads;
+ pthread_t *threads;
+ int nthreads;
};
struct _threadpool_job {
UiThreadpool* threadpool_new(int min, int max);
int threadpool_start(UiThreadpool *pool);
+int threadpool_join(UiThreadpool *pool);
void* threadpool_func(void *data);
threadpool_job* threadpool_get_job(UiThreadpool *pool);
void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data);
-void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job);
+
+UiQueue* ui_queue_create(void);
+void ui_queue_free(UiQueue *queue);
+void ui_queue_put(UiQueue *queue, void *data);
+void* ui_queue_get_wait(UiQueue *queue);
#ifdef __cplusplus
}
newargs.tooltip = nl_strdup(args->tooltip);\r
newargs.onclick = args->onclick;\r
newargs.onclickdata = args->onclickdata;\r
- newargs.groups = uic_copy_groups(args->groups, ngroups);\r
- newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\r
+ newargs.states = uic_copy_states(args->states, ngroups);\r
+ newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
return newargs;\r
}\r
\r
void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args) {\r
UiToolbarItem* item = malloc(sizeof(UiToolbarItem));\r
item->item.type = UI_TOOLBAR_ITEM;\r
- item->args = itemargs_copy(args, &item->ngroups, &item->nvstates);\r
+ item->args = itemargs_copy(args, &item->nstates, &item->nvstates);\r
cxMapPut(toolbar_items, name, item);\r
}\r
\r
newargs.varname = nl_strdup(args->varname);\r
newargs.onchange = args->onchange;\r
newargs.onchangedata = args->onchangedata;\r
- newargs.groups = uic_copy_groups(args->groups, ngroups);\r
- newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\r
+ newargs.states = uic_copy_states(args->states, ngroups);\r
+ newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
return newargs;\r
}\r
\r
void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args) {\r
UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem));\r
item->item.type = UI_TOOLBAR_TOGGLEITEM;\r
- item->args = toggleitemargs_copy(args, &item->ngroups, &item->nvstates);\r
+ item->args = toggleitemargs_copy(args, &item->nstates, &item->nvstates);\r
cxMapPut(toolbar_items, name, item);\r
}\r
\r
newargs.label = nl_strdup(args->label);\r
newargs.icon = nl_strdup(args->icon);\r
newargs.tooltip = nl_strdup(args->tooltip);\r
- newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);\r
+ newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates);\r
return newargs;\r
}\r
\r
struct UiToolbarItem {\r
UiToolbarItemI item;\r
UiToolbarItemArgs args;\r
- size_t ngroups;\r
+ size_t nstates;\r
size_t nvstates;\r
};\r
\r
struct UiToolbarToggleItem {\r
UiToolbarItemI item;\r
UiToolbarToggleItemArgs args;\r
- size_t ngroups;\r
+ size_t nstates;\r
size_t nvstates;\r
};\r
\r
#include <cx/list.h>
#include <cx/array_list.h>
-#include "../ui/tree.h"
+#include "../ui/list.h"
#include "types.h"
#include "context.h"
#include "../ui/image.h"
static ui_list_init_func default_list_init;
static void *default_list_init_userdata;
+static ui_list_destroy_func default_list_destroy;
+static void *default_list_destroy_userdata;
UiObserver* ui_observer_new(ui_callback f, void *data) {
UiObserver *observer = malloc(sizeof(UiObserver));
list->count = ui_list_count;
}
+void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused) {
+ cxListFree(list->data);
+ ui_free(ctx, list);
+}
+
UiList* ui_list_new(UiContext *ctx, const char *name) {
return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata);
}
return list;
}
-void ui_list_free(UiList *list) {
- cxListFree(list->data);
- free(list);
+void ui_list_free(UiContext *ctx, UiList *list) {
+ if(!default_list_destroy) {
+ uic_ucx_list_destroy(ctx, list, NULL);
+ } else {
+ default_list_destroy(ctx, list, default_list_destroy_userdata);
+ }
+
}
void* ui_list_first(UiList *list) {
UiModel* ui_model(UiContext *ctx, ...) {
UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
+ info->ctx = ctx;
va_list ap;
va_start(ap, ctx);
#define UI_MODEL_DEFAULT_ALLOC_SIZE 16
+
+static void model_notify_observer(UiModel *model, int insert, int delete) {
+ UiModelChangeObserver *obs = model->observer;
+ while(obs) {
+ obs->update(model, obs->userdata, insert, delete);
+ obs = obs->next;
+ }
+}
+
UiModel* ui_model_new(UiContext *ctx) {
UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
+ info->ctx = ctx;
info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE;
info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType));
info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*));
return info;
}
-void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width) {
+void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width) {
+ UiContext *ctx = model->ctx;
if(model->columns >= model->alloc) {
model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE;
model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType));
model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*));
model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int));
}
- model->types[model->columns] = type;
- model->titles[model->columns] = ui_strdup(ctx, title);
- model->columnsize[model->columns] = width;
+ int index = model->columns;
+ model->types[index] = type;
+ model->titles[index] = ui_strdup(ctx, title);
+ model->columnsize[index] = width;
+
+ model_notify_observer(model, index, -1);
+
model->columns++;
}
const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
UiModel* newmodel = cxMalloc(a, sizeof(UiModel));
+ newmodel->ctx = ctx;
*newmodel = *model;
newmodel->types = cxCalloc(a, model->columns, sizeof(UiModelType));
return newmodel;
}
-void ui_model_free(UiContext *ctx, UiModel *mi) {
- const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
+void ui_model_ref(UiModel *model) {
+ model->ref++;
+}
+
+void ui_model_unref(UiModel *model) {
+ if(--model->ref == 0) {
+ ui_model_free(model);
+ }
+}
+
+void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data) {
+ UiModelChangeObserver *observer = ui_malloc(model->ctx, sizeof(UiModelChangeObserver));
+ observer->update = update;
+ observer->userdata = data;
+ observer->next = NULL;
+
+ if(model->observer) {
+ UiModelChangeObserver *last = model->observer;
+ while(last->next) {
+ last = last->next;
+ }
+ last->next = observer;
+ } else {
+ model->observer = observer;
+ }
+}
+
+void ui_model_remove_observer(UiModel *model, void *data) {
+ if(model->observer) {
+ UiModelChangeObserver *obs = model->observer;
+ UiModelChangeObserver *prev = NULL;
+ while(obs) {
+ if(obs->userdata == data) {
+ // remove
+ if(prev) {
+ prev->next = obs->next;
+ } else {
+ model->observer = obs->next;
+ }
+ // free
+ ui_free(model->ctx, obs);
+ break;
+ }
+ prev = obs;
+ obs = obs->next;
+ }
+ }
+}
+
+void ui_model_free(UiModel *mi) {
+ UiContext *ctx = mi->ctx;
+ const CxAllocator* a = ctx->allocator;
for(int i=0;i<mi->columns;i++) {
ui_free(ctx, mi->titles[i]);
}
+ UiModelChangeObserver *obs = mi->observer;
+ while(obs) {
+ UiModelChangeObserver *n = obs->next;
+ cxFree(a, obs);
+ obs = n;
+ }
cxFree(a, mi->types);
cxFree(a, mi->titles);
cxFree(a, mi->columnsize);
}
UIEXPORT void ui_listselection_free(UiListSelection selection) {
- if (selection.rows) {
- free(selection.rows);
- }
+ free(selection.rows);
}
UIEXPORT UiStr ui_str(char *cstr) {
}
static int ui_set_op = 0;
+static int ui_onchange_events_enabled = TRUE;
void ui_setop_enable(int set) {
ui_set_op = set;
return ui_set_op;
}
+void ui_onchange_events_enable(UiBool enable) {
+ ui_onchange_events_enabled = enable;
+}
+
+UiBool ui_onchange_events_is_enabled(void) {
+ return ui_onchange_events_enabled;
+}
+
/* ---------------- List initializers and wrapper functions ---------------- */
void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
default_list_init_userdata = userdata;
}
+void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) {
+ default_list_destroy = func;
+ default_list_destroy_userdata = userdata;
+}
+
void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
list->first = first;
}
#endif
void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused);
+void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused);
void uic_int_copy(UiInteger *from, UiInteger *to);
void uic_double_copy(UiDouble *from, UiDouble *to);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils.h"
+#include "properties.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <cx/string.h>
+#include <cx/buffer.h>
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) {
+ cxstring *pathelms;
+ size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms);
+
+ if (nelm == 0) {
+ *ret_nelm = 0;
+ return NULL;
+ }
+
+ UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm));
+ size_t n = nelm;
+ int j = 0;
+ for (int i = 0; i < nelm; i++) {
+ cxstring c = pathelms[i];
+ if (c.length == 0) {
+ if (i == 0) {
+ c.length = 1;
+ }
+ else {
+ n--;
+ continue;
+ }
+ }
+
+ cxmutstr m = cx_strdup(c);
+ elms[j].name = m.ptr;
+ elms[j].name_len = m.length;
+
+ size_t elm_path_len = c.ptr + c.length - full_path;
+ cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
+ elms[j].path = elm_path.ptr;
+ elms[j].path_len = elm_path.length;
+
+ j++;
+ }
+ *ret_nelm = n;
+
+ return elms;
+}
+
+void ui_get_window_default_width(int *width, int *height) {
+ const char *width_str = ui_get_property("ui.window.width");
+ const char *height_str = ui_get_property("ui.window.height");
+ if(width_str && height_str) {
+ int w = atoi(width_str);
+ int h = atoi(height_str);
+ if(w > 0 && h > 0) {
+ *width = w;
+ *height = h;
+ }
+ }
+}
+
+// from UCX json.c
+static cxmutstr escape_string(cxstring str, bool escape_slash) {
+ // note: this function produces the string without enclosing quotes
+ // the reason is that we don't want to allocate memory just for that
+ CxBuffer buf = {0};
+
+ bool all_printable = true;
+ for (size_t i = 0; i < str.length; i++) {
+ unsigned char c = str.ptr[i];
+ bool escape = c < 0x20 || c == '\\' || c == '"'
+ || (escape_slash && c == '/');
+
+ if (all_printable && escape) {
+ size_t capa = str.length + 32;
+ char *space = cxMallocDefault(capa);
+ if (space == NULL) return cx_mutstrn(NULL, 0);
+ cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND);
+ cxBufferWrite(str.ptr, 1, i, &buf);
+ all_printable = false;
+ }
+ if (escape) {
+ cxBufferPut(&buf, '\\');
+ if (c == '\"') {
+ cxBufferPut(&buf, '\"');
+ } else if (c == '\n') {
+ cxBufferPut(&buf, 'n');
+ } else if (c == '\t') {
+ cxBufferPut(&buf, 't');
+ } else if (c == '\r') {
+ cxBufferPut(&buf, 'r');
+ } else if (c == '\\') {
+ cxBufferPut(&buf, '\\');
+ } else if (c == '/') {
+ cxBufferPut(&buf, '/');
+ } else if (c == '\f') {
+ cxBufferPut(&buf, 'f');
+ } else if (c == '\b') {
+ cxBufferPut(&buf, 'b');
+ } else {
+ char code[6];
+ snprintf(code, sizeof(code), "u%04x", (unsigned int) c);
+ cxBufferPutString(&buf, code);
+ }
+ } else if (!all_printable) {
+ cxBufferPut(&buf, c);
+ }
+ }
+ cxmutstr ret;
+ if (all_printable) {
+ // don't copy the string when we don't need to escape anything
+ ret = cx_mutstrn((char*)str.ptr, str.length);
+ } else {
+ ret = cx_mutstrn(buf.space, buf.size);
+ }
+ cxBufferDestroy(&buf);
+ return ret;
+}
+
+cxmutstr ui_escape_string(cxstring str) {
+ return escape_string(str, FALSE);
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UIC_UTILS_H
+#define UIC_UTILS_H
+
+#include "../ui/toolkit.h"
+#include "../ui/text.h"
+
+#include <cx/string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data);
+
+/*
+ * overrides width/height with values from
+ * ui.window.width and ui.window.height properties if available
+ */
+void ui_get_window_default_width(int *width, int *height);
+
+cxmutstr ui_escape_string(cxstring str);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_UTILS_H */
+
cxListRemove(cxlist, index);
}
+void ui_srclist_swap(UiList *list, int i1, int i2) {
+ CxList *cxlist = list->data;
+ cxListSwap(cxlist, i1, i2);
+}
+
void ui_srclist_clear(UiList *list) {
CxList *cxlist = list->data;
cxListClear(cxlist);
#define UIC_WRAPPER_H
#include "../ui/toolkit.h"
-#include "../ui/tree.h"
+#include "../ui/list.h"
#ifdef __cplusplus
extern "C" {
UIEXPORT void ui_srclist_add(UiList *list, UiSubList *item);
UIEXPORT void ui_srclist_insert(UiList *list, int index, UiSubList *item);
UIEXPORT void ui_srclist_remove(UiList *list, int index);
+UIEXPORT void ui_srclist_swap(UiList *list, int i1, int i2);
UIEXPORT void ui_srclist_clear(UiList *list);
UIEXPORT int ui_srclist_size(UiList *list);
UIEXPORT void ui_srclist_generate_sublist_num_data(UiList *list);
UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, 0, FALSE);
ui_set_name_and_style(button, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, button, args->groups);
+ ui_set_widget_states(obj->ctx, button, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, button, &layout);
static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) {
if(gtk_toggle_button_get_active(widget)) {
- ui_set_group(event->obj->ctx, event->value);
+ ui_set_state(event->obj->ctx, event->value);
} else {
- ui_unset_group(event->obj->ctx, event->value);
+ ui_unset_state(event->obj->ctx, event->value);
}
}
args->value,
args->onchange,
args->onchangedata,
- args->enable_group);
+ args->enable_state);
ui_set_name_and_style(widget, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, widget, args->groups);
+ ui_set_widget_states(obj->ctx, widget, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event) {
if(gtk_check_button_get_active(widget)) {
- ui_set_group(event->obj->ctx, event->value);
+ ui_set_state(event->obj->ctx, event->value);
} else {
- ui_unset_group(event->obj->ctx, event->value);
+ ui_unset_state(event->obj->ctx, event->value);
}
}
args->onchange,
args->onchangedata,
(ui_toggled_func)ui_checkbox_enable_state,
- args->enable_group);
+ args->enable_state);
ui_set_name_and_style(widget, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, widget, args->groups);
+ ui_set_widget_states(obj->ctx, widget, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
GtkWidget *widget = gtk_switch_new();
ui_set_name_and_style(widget, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, widget, args->groups);
+ ui_set_widget_states(obj->ctx, widget, args->states);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args->label);
ui_set_name_and_style(rbutton, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, rbutton, args->groups);
+ ui_set_widget_states(obj->ctx, rbutton, args->states);
if(rgroup) {
#if GTK_MAJOR_VERSION >= 4
if(rg) {
}
ui_set_name_and_style(button, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, button, args->groups);
+ ui_set_widget_states(obj->ctx, button, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, button, &layout);
return add;
}
+/* -------------------- Custom Container -------------------- */
+
+void ui_custom_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+ UiCustomContainer *custom = (UiCustomContainer*)ct;
+ custom->add(custom->obj, ct->widget, widget, custom->userdata);
+}
+
+void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_func add_child, void *userdata) {
+ UiCustomContainer *container = cxZalloc(obj->ctx->allocator, sizeof(UiCustomContainer));
+ container->container.add = ui_custom_container_add;
+ container->container.widget = widget;
+ container->add = add_child;
+ container->userdata = userdata;
+ uic_object_push_container(obj, (UiContainerX*)container);
+}
/* -------------------- Box Container -------------------- */
UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
hb->centerbox = box;
UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box);
+ UI_HEADERBAR_SHOW_TITLE_WIDGET(ct->widget, TRUE);
+ UI_HEADERBAR_SETTINGS(ct->widget);
}
BOX_ADD(hb->centerbox, widget);
}
UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init) {
UiSplitPane *ct = malloc(sizeof(UiSplitPane));
+ memset(ct, 0, sizeof(UiSplitPane));
ct->current_pane = pane;
ct->orientation = orientation;
ct->max = max;
int close;
};
+typedef struct UiCustomContainer {
+ UiContainerPrivate container;
+ UiObject *obj;
+ ui_addwidget_func add;
+ void *userdata;
+} UiCustomContainer;
+
typedef struct UiBoxContainer {
UiContainerPrivate container;
UiSubContainerType type;
#endif
GtkWidget *spin = gtk_spin_button_new_with_range(min, max, args->step);
ui_set_name_and_style(spin, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, spin, args->groups);
+ ui_set_widget_states(obj->ctx, spin, args->states);
if(args->width > 0) {
gtk_widget_set_size_request(spin, args->width, -1);
widget,
"draw",
G_CALLBACK(draw_callback),
- NULL);
+ drawingarea);
#endif
g_signal_connect(
- widget,
- "destroy",
- G_CALLBACK(destroy_drawingarea),
- drawingarea);
+ widget,
+ "destroy",
+ G_CALLBACK(destroy_drawingarea),
+ drawingarea);
return widget;
}
enum UiToolbarPos pos)
{
GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, 0, FALSE);
- ui_set_widget_groups(obj->ctx, button, item->args.groups);
+ ui_set_widget_states(obj->ctx, button, item->args.states);
ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
WIDGET_ADD_CSS_CLASS(button, "flat");
headerbar_add(headerbar, box, button, pos);
enum UiToolbarPos pos)
{
GtkWidget *button = gtk_toggle_button_new();
- ui_set_widget_groups(obj->ctx, button, item->args.groups);
+ ui_set_widget_states(obj->ctx, button, item->args.states);
ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
WIDGET_ADD_CSS_CLASS(button, "flat");
ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, 0);
#define UI_HEADERBAR_PACK_START(h, w) adw_header_bar_pack_start(ADW_HEADER_BAR(h), w)
#define UI_HEADERBAR_PACK_END(h, w) adw_header_bar_pack_end(ADW_HEADER_BAR(h), w)
#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) adw_header_bar_set_title_widget(ADW_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) adw_header_bar_set_show_title(ADW_HEADER_BAR(h), b)
+#define UI_HEADERBAR_SETTINGS(h) adw_header_bar_set_centering_policy(ADW_HEADER_BAR(h), ADW_CENTERING_POLICY_LOOSE)
#else
#define UI_HEADERBAR GtkHeaderBar*
#define UI_HEADERBAR_CAST(h) GTK_HEADER_BAR(h)
#define UI_HEADERBAR_PACK_START(h, w) gtk_header_bar_pack_start(GTK_HEADER_BAR(h), w)
#define UI_HEADERBAR_PACK_END(h, w) gtk_header_bar_pack_end(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SETTINGS(h)
#if GTK_MAJOR_VERSION >= 4
#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_title_widget(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) gtk_header_bar_set_show_title(GTK_HEADER_BAR(h), b)
#else
#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_custom_title(GTK_HEADER_BAR(h), w)
+#define UI_HEADERBAR_SHOW_TITLE_WIDGET(h, b) gtk_header_bar_set_show_title(GTK_HEADER_BAR(h), b)
#endif
#endif
#include "container.h"
#include "menu.h"
+#include "widget.h"
#include "../common/context.h"
#include "../common/object.h"
GtkWidget *drawingarea = gtk_drawing_area_new();
GtkWidget *toplevel;
GtkWidget *widget = drawingarea;
-
- gtk_widget_set_size_request(drawingarea, 100, 100);
+
+ int width = args->width;
+ int height = args->height;
+ if(width == 0 && height == 0) {
+ width = 100;
+ height = 100;
+ }
+ ui_widget_size_request(drawingarea, width, height);
#if GTK_MAJOR_VERSION < 4
GtkWidget *eventbox = gtk_event_box_new();
memset(tableview, 0, sizeof(UiListView));
tableview->obj = obj;
tableview->model = args->model;
+ tableview->multiselection = args->multiselection;
tableview->onactivate = args->onactivate;
tableview->onactivatedata = args->onactivatedata;
tableview->onselection = args->onselection;
tableview->onsave = args->onsave;
tableview->onsavedata = args->onsavedata;
+#if GTK_CHECK_VERSION(4, 0, 0)
+ tableview->coldata.listview = tableview;
+ tableview->coldata.column = 0;
+#endif
+
if(args->getvalue2) {
tableview->getvalue = args->getvalue2;
tableview->getvaluedata = args->getvalue2data;
static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
UiColData *col = userdata;
UiModel *model = col->listview->model;
- UiModelType type = model->types[col->model_column];
+ UiModelType type = model->types[col->column];
if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
GtkWidget *image = gtk_image_new();
UiColData *col = userdata;
UiList *list = col->listview->var ? col->listview->var->value : NULL;
UiListView *listview = col->listview;
+ int datacolumn = listview->columns[col->column];
ObjWrapper *obj = gtk_list_item_get_item(item);
UiModel *model = col->listview->model;
- UiModelType type = model->types[col->model_column];
+ UiModelType type = model->types[col->column];
// cache the GtkListItem
CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
if(row) {
- if(row->items[col->model_column] == NULL) {
+ if(row->items[col->column] == NULL) {
row->bound++;
}
} else {
cxMapPut(listview->bound_rows, row_key, row);
row->bound = 1;
}
- row->items[col->model_column] = item;
+ row->items[col->column] = item;
UiBool freevalue = FALSE;
- void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
+ void *data = listview->getvalue(list, obj->data, obj->i, datacolumn, listview->getvaluedata, &freevalue);
GtkWidget *child = gtk_list_item_get_child(item);
PangoAttrList *attributes = NULL;
}
}
- int style_col = col->data_column;
+ int style_col = datacolumn;
if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
style_col++; // col->data_column is the icon, we need the next col for the label
}
}
case UI_ICON_TEXT_FREE: {
- void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue);
+ void *data2 = listview->getvalue(list, obj->data, obj->i, datacolumn+1, listview->getvaluedata, &freevalue);
if(type == UI_ICON_TEXT_FREE) {
freevalue = TRUE;
}
if(entry) {
entry->listview = col->listview;
entry->row = obj->i;
- entry->col = col->data_column;
+ entry->col = datacolumn;
entry->previous_value = strdup(data);
}
ENTRY_SET_TEXT(child, data);
}
}
-static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
+static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
ObjWrapper *obj = gtk_list_item_get_item(item);
UiListView *listview = col->listview;
CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
if(row) {
- row->items[col->model_column] = NULL;
+ row->items[col->column] = NULL;
row->bound--;
if(row->bound == 0) {
cxMapRemove(listview->bound_rows, row_key);
}
listview->numcolumns = 1;
- listview->columns = malloc(sizeof(UiColData));
- listview->columns->listview = listview;
- listview->columns->data_column = 0;
- listview->columns->model_column = 0;
+ listview->columns = malloc(sizeof(int));
+ listview->columns[0] = 0;
listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
- g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
- g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+ g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
+ g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
+ g_signal_connect(factory, "unbind", G_CALLBACK(column_factory_unbind), &listview->coldata);
GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
return scroll_area;
}
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
+UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
// to simplify things and share code with ui_tableview_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
}
listview->numcolumns = 1;
- listview->columns = malloc(sizeof(UiColData));
- listview->columns->listview = listview;
- listview->columns->data_column = 0;
- listview->columns->model_column = 0;
+ listview->columns = malloc(sizeof(int));
+ listview->columns[0] = 0;
listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
- g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
- g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+ g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
+ g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
list->obj = listview;
list->update = ui_listview_update2;
- list->getselection = ui_combobox_getselection;
- list->setselection = ui_combobox_setselection;
+ list->getselection = ui_dropdown_getselection;
+ list->setselection = ui_dropdown_setselection;
ui_update_liststore(ls, list);
} else if (args->static_elements && args->static_nelm > 0) {
gtk_selection_model_select_item(model, index, TRUE);
}
-void ui_combobox_select(UIWIDGET dropdown, int index) {
+void ui_dropdown_select(UIWIDGET dropdown, int index) {
gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
}
+static void add_column(UiListView *tableview, int index) {
+ UiModel *model = tableview->model;
+
+ UiColData *col = malloc(sizeof(UiColData));
+ col->listview = tableview;
+ col->column = index;
+
+ GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+ g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
+ g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
+ g_object_set_data_full(G_OBJECT(factory), "coldata", col, (GDestroyNotify)free);
+
+ GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[index], factory);
+ gtk_column_view_column_set_resizable(column, true);
+ gtk_column_view_insert_column(GTK_COLUMN_VIEW(tableview->widget), index, column);
+
+ int size = model->columnsize[index];
+ if(size > 0) {
+ gtk_column_view_column_set_fixed_width(column, size);
+ } else if(size < 0) {
+ gtk_column_view_column_set_expand(column, TRUE);
+ }
+}
+
UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
//g_list_store_append(ls, v1);
// create columns from UiModel
UiModel *model = args->model;
- int columns = model ? model->columns : 0;
+ int columns = 0;
+ if(model) {
+ columns = model->columns;
+ ui_model_add_observer(model, ui_listview_update_model, tableview);
+ }
- tableview->columns = calloc(columns, sizeof(UiColData));
+ tableview->columns = calloc(columns, sizeof(int));
tableview->numcolumns = columns;
tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
int addi = 0;
for(int i=0;i<columns;i++) {
- tableview->columns[i].listview = tableview;
- tableview->columns[i].model_column = i;
- tableview->columns[i].data_column = i+addi;
+ tableview->columns[i] = i+addi;
if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
// icon+text has 2 data columns
addi++;
}
- GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
- UiColData *col = &tableview->columns[i];
- g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
- g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
-
- GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[i], factory);
- gtk_column_view_column_set_resizable(column, true);
- gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column);
-
- int size = model->columnsize[i];
- if(size > 0) {
- gtk_column_view_column_set_fixed_width(column, size);
- } else if(size < 0) {
- gtk_column_view_column_set_expand(column, TRUE);
- }
+ add_column(tableview, i);
}
// bind listview to list
return scroll_area;
}
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index) {
+ UiListView *listview = userdata;
+ if(insert_index >= listview->numcolumns) {
+ listview->numcolumns = insert_index+1;
+ listview->columns = realloc(listview->columns, listview->numcolumns * sizeof(UiColData));
+ }
+
+ gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), NULL);
+ cxMapClear(listview->bound_rows);
+
+ if(insert_index) {
+ int prev = 0;
+ if(insert_index > 0) {
+ prev = listview->columns[insert_index-1];
+ }
+ listview->columns[insert_index] = prev+1;
+ add_column(listview, insert_index);
+
+ if(insert_index+1 < listview->numcolumns) {
+ // the data index of trailing columns must be adjusted
+ UiModelType type = model->types[insert_index];
+ int add = 1;
+ if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+ add++;
+ }
+ for(int i=insert_index+1;i<listview->numcolumns;i++) {
+ listview->columns[i] += add;
+ }
+ }
+ } // TODO: delete_index
+
+ GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
+ GtkSelectionModel *selection_model = create_selection_model(listview, ls, listview->multiselection);
+ gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), selection_model);
+ listview->selectionmodel = selection_model;
+ listview->liststore = ls;
+
+ if(listview->var) {
+ UiList *list = listview->var->value;
+ ui_list_update(list);
+ }
+}
+
static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
UiListSelection sel = { 0, NULL };
GtkBitset *bitset = gtk_selection_model_get_selection(model);
void ui_listview_update2(UiList *list, int i) {
UiListView *view = list->obj;
+ view->current_row = -1;
if(i < 0) {
+ cxMapClear(view->bound_rows);
ui_update_liststore(view->liststore, list);
} else {
void *value = list->get(list, i);
CxHashKey row_key = cx_hash_key(&i, sizeof(int));
UiRowItems *row = cxMapGet(view->bound_rows, row_key);
if(row) {
+ UiColData coldata;
+ coldata.listview = view;
for(int c=0;c<view->numcolumns;c++) {
if(row->items[c] != NULL) {
- column_factory_bind(NULL, row->items[c], &view->columns[c]);
+ coldata.column = c;
+ column_factory_bind(NULL, row->items[c], &coldata);
}
}
}
ui_setop_enable(FALSE);
}
-UiListSelection ui_combobox_getselection(UiList *list) {
+UiListSelection ui_dropdown_getselection(UiList *list) {
UiListView *view = list->obj;
guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget));
UiListSelection sel = { 0, NULL };
return sel;
}
-void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
ui_setop_enable(TRUE);
UiListView *view = list->obj;
if(selection.count > 0) {
// create treeview
GtkWidget *view = gtk_tree_view_new();
ui_set_name_and_style(view, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, view, args->groups);
+ ui_set_widget_states(obj->ctx, view, args->states);
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
//g_object_unref(path);
}
-void ui_combobox_select(UIWIDGET dropdown, int index) {
+void ui_dropdown_select(UIWIDGET dropdown, int index) {
gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
}
-/* --------------------------- ComboBox --------------------------- */
+/* --------------------------- Dropdown --------------------------- */
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
+UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
GtkWidget *combobox = gtk_combo_box_new();
if(args->width > 0) {
gtk_widget_set_size_request(combobox, args->width, -1);
}
ui_set_name_and_style(combobox, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, combobox, args->groups);
+ ui_set_widget_states(obj->ctx, combobox, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, combobox, &layout);
if(var) {
listview->var = var;
list->update = ui_combobox_modelupdate;
- list->getselection = ui_combobox_getselection;
- list->setselection = ui_combobox_setselection;
+ list->getselection = ui_dropdown_getselection;
+ list->setselection = ui_dropdown_setselection;
list->obj = listview;
list->update(list, -1);
} else if(args->static_nelm > 0) {
g_object_unref(store);
}
-UiListSelection ui_combobox_getselection(UiList *list) {
+UiListSelection ui_dropdown_getselection(UiList *list) {
UiListView *combobox = list->obj;
UiListSelection ret;
ret.rows = malloc(sizeof(int*));
return ret;
}
-void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
ui_setop_enable(TRUE);
UiListView *combobox = list->obj;
if(selection.count > 0) {
if(v->var) {
ui_destroy_boundvar(v->obj->ctx, v->var);
}
+ if(v->model) {
+ ui_model_remove_observer(v->model, v);
+ ui_model_unref(v->model);
+ }
if(v->elements) {
for(int i=0;i<v->nelm;i++) {
free(v->elements[i]);
UiList *list = uisublist.var->value;
list->obj = sublist_ptr;
list->update = ui_listbox_list_update;
+ list->getselection = ui_listbox_list_getselection;
+ list->setselection = ui_listbox_list_setselection;
}
}
SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
ui_set_name_and_style(listbox, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, listbox, args->groups);
+ ui_set_widget_states(obj->ctx, listbox, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, scroll_area, &layout);
UiList *list = var->value;
list->obj = uilistbox;
list->update = ui_listbox_dynamic_update;
+ list->getselection = ui_listbox_dynamic_getselection;
+ list->setselection = ui_listbox_dynamic_setselection;
ui_listbox_dynamic_update(list, -1);
}
ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
}
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel) {
+ UiListBox *uilistbox = list->obj;
+ gtk_list_box_unselect_all(uilistbox->listbox);
+ if(sel.count > 0) {
+ int index = sel.rows[0];
+ if(index >= 0) {
+ GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, index);
+ if(row) {
+ gtk_list_box_select_row(uilistbox->listbox, row);
+ }
+ }
+ }
+}
+
+UiListSelection ui_listbox_dynamic_getselection(UiList *list) {
+ UiListSelection sel = { 0, NULL };
+ UiListBox *uilistbox = list->obj;
+ GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+ if(row) {
+ sel.count = 1;
+ sel.rows = malloc(sizeof(int));
+ sel.rows[0] = gtk_list_box_row_get_index(row);
+ }
+ return sel;
+}
+
void ui_listbox_update(UiListBox *listbox, int from, int to) {
CxIterator i = cxListIterator(listbox->sublists);
size_t pos = 0;
ui_sourcelist_update_finished();
}
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel) {
+ UiListBoxSubList *sublist = list->obj;
+ UiListBox *uilistbox = sublist->listbox;
+ gtk_list_box_unselect_all(uilistbox->listbox);
+ if(sel.count > 0) {
+ int index = sel.rows[0];
+ if(index >= 0 && index < sublist->numitems) {
+ int global_index = sublist->startpos + index;
+ GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, global_index);
+ if(row) {
+ gtk_list_box_select_row(uilistbox->listbox, row);
+ }
+ }
+ }
+}
+
+UiListSelection ui_listbox_list_getselection(UiList *list) {
+ UiListSelection sel = { 0, NULL };
+ UiListBoxSubList *sublist = list->obj;
+ UiListBox *uilistbox = sublist->listbox;
+ GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+ if(row) {
+ int index = gtk_list_box_row_get_index(row);
+ size_t startpos = sublist->startpos;
+ if(index >= startpos && index < startpos+sublist->numitems) {
+ sel.count = 1;
+ sel.rows = malloc(sizeof(int));
+ sel.rows[0] = index - startpos;
+ }
+ }
+ return sel;
+}
+
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata");
if(!data) {
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TREE_H
-#define TREE_H
+#ifndef LIST_H
+#define LIST_H
-#include "../ui/tree.h"
+#include "../ui/list.h"
#include "toolkit.h"
#include <cx/array_list.h>
extern "C" {
#endif
+typedef struct UiListView UiListView;
typedef struct UiColData UiColData;
#if GTK_CHECK_VERSION(4, 10, 0)
} UiRowItems;
#endif
-typedef struct UiListView {
+struct UiColData {
+ UiListView *listview;
+ int column;
+};
+
+struct UiListView {
UiObject *obj;
GtkWidget *widget;
UiVar *var;
UiModel *model;
+ UiBool multiselection;
ui_getvaluefunc2 getvalue;
void *getvaluedata;
ui_getstylefunc getstyle;
CxMap *bound_rows;
GListStore *liststore;
GtkSelectionModel *selectionmodel;
- UiColData *columns;
+ int *columns;
int numcolumns;
+ UiColData coldata;
PangoAttrList *current_row_attributes;
#else
int style_offset;
void *onsavedata;
UiListSelection selection;
-} UiListView;
-
-struct UiColData {
- UiListView *listview;
- int model_column;
- int data_column;
};
typedef struct UiTreeEventData {
void ui_update_liststore(GListStore *liststore, UiList *list);
void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm);
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index);
void ui_listview_update2(UiList *list, int i);
UiListSelection ui_listview_getselection2(UiList *list);
void ui_listview_setselection2(UiList *list, UiListSelection selection);
GtkWidget* ui_get_tree_widget(UIWIDGET widget);
+void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index);
void ui_listview_update(UiList *list, int i);
UiListSelection ui_listview_getselection(UiList *list);
void ui_listview_setselection(UiList *list, UiListSelection selection);
GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata);
void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e);
void ui_combobox_modelupdate(UiList *list, int i);
-UiListSelection ui_combobox_getselection(UiList *list);
-void ui_combobox_setselection(UiList *list, UiListSelection selection);
+UiListSelection ui_dropdown_getselection(UiList *list);
+void ui_dropdown_setselection(UiList *list, UiListSelection selection);
void ui_listbox_dynamic_update(UiList *list, int i);
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_dynamic_getselection(UiList *list);
+
void ui_listbox_update(UiListBox *listbox, int from, int to);
void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index);
void ui_listbox_list_update(UiList *list, int i);
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_list_getselection(UiList *list);
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data);
}
#endif
-#endif /* TREE_H */
+#endif /* LIST_H */
gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
- if(i->groups) {
- CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
- cxListAddArray(groups, i->groups, i->ngroups);
- uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
- cxListFree(groups);
+ if(i->states) {
+ CxList *states = cxArrayListCreateSimple(sizeof(int), i->nstates);
+ cxListAddArray(states, i->states, i->nstates);
+ uic_add_state_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, states);
+ cxListFree(states);
}
}
g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
g_object_unref(action);
- if(i->groups) {
- CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
- cxListAddArray(groups, i->groups, i->ngroups);
- uic_add_group_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups);
+ if(i->states) {
+ CxList *groups = cxArrayListCreateSimple(sizeof(int), i->nstates);
+ cxListAddArray(groups, i->states, i->nstates);
+ uic_add_state_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups);
cxListFree(groups);
}
#include "text.h"
#include "container.h"
+#include "widget.h"
#include <cx/printf.h>
int sel = gtk_text_buffer_get_selection_bounds (buf, &begin, &end);
if(sel != textview->last_selection_state) {
if(sel) {
- ui_set_group(textview->ctx, UI_GROUP_SELECTION);
+ ui_set_state(textview->ctx, UI_GROUP_SELECTION);
} else {
- ui_unset_group(textview->ctx, UI_GROUP_SELECTION);
+ ui_unset_state(textview->ctx, UI_GROUP_SELECTION);
}
}
textview->last_selection_state = sel;
GtkWidget *text_area = gtk_text_view_new();
ui_set_name_and_style(text_area, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, text_area, args->groups);
+ ui_set_widget_states(obj->ctx, text_area, args->states);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR);
g_signal_connect(
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area);
- if(args->width > 0 || args->height > 0) {
- int width = args->width;
- int height = args->height;
- if(width == 0) {
- width = -1;
- }
- if(height == 0) {
- height = -1;
- }
- gtk_widget_set_size_request(scroll_area, width, height);
- }
+ ui_widget_size_request(scroll_area, args->width, args->height);
// font and padding
//PangoFontDescription *font;
void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
+ if(!ui_onchange_events_is_enabled()) {
+ return;
+ }
+
UiText *value = textarea->var->value;
UiEvent e;
static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool password, UiTextFieldArgs *args) {
GtkWidget *textfield = gtk_entry_new();
ui_set_name_and_style(textfield, args->name, args->style_class);
- ui_set_widget_groups(obj->ctx, textfield, args->groups);
+ ui_set_widget_states(obj->ctx, textfield, args->states);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
}
void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
- UiString *value = textfield->var->value;
+ if(!ui_onchange_events_is_enabled()) {
+ return;
+ }
+
+ UiString *value = textfield->var ? textfield->var->value : NULL;
UiEvent e;
e.obj = textfield->obj;
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
e.eventdata = value;
- e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
e.intval = 0;
e.set = ui_get_setop();
void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
if(textfield->onactivate) {
+ UiString *value = textfield->var ? textfield->var->value : NULL;
+
UiEvent e;
e.obj = textfield->obj;
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
- e.eventdata = NULL;
- e.eventdatatype = 0;
+ e.eventdata = value;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
e.intval = 0;
e.set = ui_get_setop();
textfield->onactivate(&e, textfield->onactivatedata);
pathtf->stack = gtk_stack_new();
gtk_widget_set_name(pathtf->stack, "path-textfield-box");
+ if(args->width > 0) {
+ gtk_widget_set_size_request(pathtf->stack, args->width, -1);
+ }
+
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, pathtf->stack, &layout);
G_CALLBACK(ui_path_textfield_destroy),
pathtf);
+ if(args->width > 0) {
+ gtk_widget_set_size_request(eventbox, args->width, -1);
+ }
+
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, eventbox, &layout);
}
gtk_tool_item_set_is_important(button, TRUE);
- ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups);
+ ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates);
if(item->args.onclick) {
UiEventData *event = cxMalloc(
if(item->args.tooltip) {
gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), item->args.tooltip);
}
- ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups);
+ ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER);
if(var) {
if(item->args.icon) {
ui_button_set_icon_name(button, item->args.icon);
}
- ui_set_widget_groups(obj->ctx, button, item->args.groups);
+ ui_set_widget_states(obj->ctx, button, item->args.states);
gtk_header_bar_pack_start(hb, button);
#include "../common/menu.h"
#include "../common/toolbar.h"
#include "../common/threadpool.h"
+#include "../common/app.h"
#include <cx/string.h>
#include <cx/printf.h>
static const char *application_name;
-static ui_callback startup_func;
-static void *startup_data;
-static ui_callback open_func;
-void *open_data;
-static ui_callback exit_func;
-void *exit_data;
-
static ui_callback appclose_fnc;
static void *appclose_udata;
return application_name;
}
-void ui_onstartup(ui_callback f, void *userdata) {
- startup_func = f;
- startup_data = userdata;
-}
-
-void ui_onopen(ui_callback f, void *userdata) {
- open_func = f;
- open_data = userdata;
-}
-
-void ui_onexit(ui_callback f, void *userdata) {
- exit_func = f;
- exit_data = userdata;
-}
-
void ui_app_exit_on_shutdown(UiBool exitapp) {
exit_on_shutdown = exitapp;
}
#ifdef UI_APPLICATION
static void app_startup(GtkApplication* app, gpointer userdata) {
- if(startup_func) {
- startup_func(NULL, startup_data);
- }
+ uic_application_startup(NULL);
}
static void app_activate(GtkApplication* app, gpointer userdata) {
}
static void app_shutdown(GtkApplication *app, gpointer userdata) {
- if(exit_func) {
- exit_func(NULL, exit_data);
- }
+ uic_application_exit(NULL);
ui_app_save_settings();
}
free(appid.ptr);
#else
- if(startup_func) {
- startup_func(NULL, startup_data);
- }
+ uic_application_startup(NULL);
gtk_main();
- if(exit_func) {
- exit_func(NULL, exit_data);
- }
+ uic_application_exit(NULL);
ui_app_save_settings();
#endif
if(exit_on_shutdown) {
#ifndef UI_GTK2
void ui_app_quit() {
- g_application_quit(G_APPLICATION(app));
+ g_application_quit(G_APPLICATION(app)); // TODO: fix, does not work
}
GtkApplication* ui_get_application() {
void ui_show(UiObject *obj) {
gboolean visible = gtk_widget_is_visible(obj->widget);
- uic_check_group_widgets(obj->ctx);
+ uic_check_state_widgets(obj->ctx);
#if GTK_MAJOR_VERSION >= 4
gtk_window_present(GTK_WINDOW(obj->widget));
#elif GTK_MAJOR_VERSION <= 3
#endif
}
-void ui_set_visible(UIWIDGET widget, int visible) {
+void ui_set_visible(UIWIDGET widget, UiBool visible) {
#if GTK_MAJOR_VERSION >= 4
gtk_widget_set_visible(widget, visible);
#else
if(visible) {
- gtk_widget_set_no_show_all(widget, FALSE);
gtk_widget_show_all(widget);
} else {
+ gtk_widget_set_no_show_all(widget, FALSE);
gtk_widget_hide(widget);
}
#endif
#if GTK_MAJOR_VERSION == 4
static const char *ui_gtk_css =
+".ui-entry-box {\n"
+" background-color: alpha(currentColor, 0.1);"
+" border-radius: 6px;"
+" padding: 7px;"
+"}\n"
"#path-textfield-box {\n"
" background-color: alpha(currentColor, 0.1);"
" border-radius: 6px;"
}
}
-void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups) {
- if(!groups) {
+void ui_set_widget_states(UiContext *ctx, GtkWidget *widget, const int *states) {
+ if(!states) {
return;
}
- size_t ngroups = uic_group_array_size(groups);
- ui_set_widget_ngroups(ctx, widget, groups, ngroups);
+ size_t nstates = uic_state_array_size(states);
+ ui_set_widget_nstates(ctx, widget, states, nstates);
}
-void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups) {
- if(ngroups > 0) {
- uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups);
+void ui_set_widget_nstates(UiContext *ctx, GtkWidget *widget, const int *states, size_t nstates) {
+ if(nstates > 0) {
+ uic_add_state_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, states, nstates);
ui_set_enabled(widget, FALSE);
}
}
if(!states) {
return;
}
- size_t nstates = uic_group_array_size(states);
+ size_t nstates = uic_state_array_size(states);
ui_set_widget_nvisibility_states(ctx, widget, states, nstates);
}
void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups) {
if(ngroups > 0) {
- uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_visible, states, ngroups);
+ uic_add_state_widget_i(ctx, widget, (ui_enablefunc)ui_set_visible, states, ngroups);
ui_set_visible(widget, FALSE);
}
}
int ui_get_scalefactor();
void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style);
-void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups);
-void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups);
+void ui_set_widget_states(UiContext *ctx, GtkWidget *widget, const int *states);
+void ui_set_widget_nstates(UiContext *ctx, GtkWidget *widget, const int *states, size_t nstates);
void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const int *states);
void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
#include "container.h"
#include "webview.h"
+#include "widget.h"
#ifdef UI_WEBVIEW
ui_set_name_and_style(webview, args->name, args->style_class);
+ ui_widget_size_request(webview, args->width, args->height);
+
UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
if(var) {
WebViewData *data = malloc(sizeof(WebViewData));
}
}
- ui_set_widget_groups(obj->ctx, webview, args->groups);
+ ui_set_widget_states(obj->ctx, webview, args->states);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
ct->add(ct, webview, &layout);
#include "../common/object.h"
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
+void ui_widget_size_request(UIWIDGET w, int width, int height) {
+ if(width > 0 || height > 0) {
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(w, width, height);
+ }
+}
+
+
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
UIWIDGET widget = create_widget(obj, args, userdata);
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
extern "C" {
#endif
-
+/*
+ * Sets a widget width/height.
+ *
+ * If wdith or height is 0, the dimension is not changed
+ */
+void ui_widget_size_request(UIWIDGET w, int width, int height);
#ifdef __cplusplus
#include "../common/context.h"
#include "../common/menu.h"
#include "../common/toolbar.h"
+#include "../common/utils.h"
#include <cx/mempool.h>
ui_set_property("ui.window.splitview.pos", buf);
}
-static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool splitview, UiBool simple) {
+static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitview, UiBool simple) {
UiObject *obj = uic_object_new_toplevel();
#ifdef UI_LIBADWAITA
obj->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
#endif
- obj->window = window_data;
-
#if GTK_CHECK_VERSION(4, 0, 0)
obj->ctx->action_map = G_ACTION_MAP(obj->widget);
#endif
int window_width = window_default_width;
int window_height = window_default_height;
if(!simple) {
- const char *width = ui_get_property("ui.window.width");
- const char *height = ui_get_property("ui.window.height");
- if(width && height) {
- int w = atoi(width);
- int h = atoi(height);
- if(w > 0 && h > 0) {
- window_width = w;
- window_height = h;
- }
- }
+ ui_get_window_default_width(&window_width, &window_height);
}
gtk_window_set_default_size(
GTK_WINDOW(obj->widget),
obj);
#endif
+ int splitview_pos = 0;
+ if(splitview) {
+ const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos");
+ splitview_pos= splitview_window_default_pos;
+ if(splitview_pos < 0) {
+ splitview_pos = window_width / 2;
+ }
+ if(splitview_pos_str && splitview_window_use_prop) {
+ int sv_pos = atoi(splitview_pos_str);
+ if(sv_pos > 0) {
+ splitview_pos = sv_pos;
+ }
+ }
+ }
+
GtkWidget *vbox = ui_gtk_vbox_new(0);
#ifdef UI_LIBADWAITA
GtkWidget *toolbar_view = adw_toolbar_view_new();
G_CALLBACK(save_window_splitview_pos),
NULL);
- const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos");
- int pos = splitview_window_default_pos;
- if(pos < 0) {
- pos = window_width / 2;
- }
- if(splitview_pos_str && splitview_window_use_prop) {
- int splitview_pos = atoi(splitview_pos_str);
- if(splitview_pos > 0) {
- pos = splitview_pos;
- }
- }
- gtk_paned_set_position(GTK_PANED(content), pos);
+ gtk_paned_set_position(GTK_PANED(content), splitview_pos);
GtkWidget *right_panel = adw_toolbar_view_new();
GtkWidget *right_vbox = ui_gtk_vbox_new(0);
GtkWidget *content_box = ui_gtk_vbox_new(0);
WINDOW_SET_CONTENT(obj->widget, vbox);
- if(sidebar) {
+ if(sidebar || splitview) {
GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
- GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0);
- gtk_paned_add1(GTK_PANED(paned), sidebar_vbox);
- gtk_paned_add2(GTK_PANED(paned), content_box);
+ if(sidebar) {
+ GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0);
+ gtk_paned_add1(GTK_PANED(paned), sidebar_vbox);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox);
+ gtk_paned_set_position(GTK_PANED(paned), 200);
+ }
+
+ if(splitview) {
+ GtkWidget *content_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+ gtk_paned_set_position(GTK_PANED(content_paned), splitview_pos);
+ gtk_paned_add2(GTK_PANED(paned), content_paned);
+
+ GtkWidget *right_content_box = ui_gtk_vbox_new(0);
+ gtk_paned_add1(GTK_PANED(content_paned), content_box);
+ gtk_paned_add2(GTK_PANED(content_paned), right_content_box);
+
+ g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content_paned);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", content_box);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_content_box);
+ } else {
+ gtk_paned_add2(GTK_PANED(paned), content_box);
+ }
+
BOX_ADD_EXPAND(GTK_BOX(vbox), paned);
- g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox);
- gtk_paned_set_position (GTK_PANED(paned), 200);
} else {
BOX_ADD_EXPAND(GTK_BOX(vbox), content_box);
}
}
-UiObject* ui_window(const char *title, void *window_data) {
- return create_window(title, window_data, FALSE, FALSE, FALSE);
+UiObject* ui_window(const char *title) {
+ return create_window(title, FALSE, FALSE, FALSE);
}
-UiObject *ui_sidebar_window(const char *title, void *window_data) {
- return create_window(title, window_data, TRUE, FALSE, FALSE);
+UiObject *ui_sidebar_window(const char *title) {
+ return create_window(title, TRUE, FALSE, FALSE);
}
-UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
- return create_window(title, NULL, sidebar, TRUE, FALSE);
+UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
+ return create_window(title, sidebar, TRUE, FALSE);
}
-UiObject* ui_simple_window(const char *title, void *window_data) {
- return create_window(title, window_data, FALSE, FALSE, TRUE);
+UiObject* ui_simple_window(const char *title) {
+ return create_window(title, FALSE, FALSE, TRUE);
}
void ui_window_size(UiObject *obj, int width, int height) {
ui_callback onclick;
void *onclickdata;
- const int *groups;
+ const int *states;
} UiButtonArgs;
typedef struct UiToggleArgs {
const char *varname;
ui_callback onchange;
void *onchangedata;
- int enable_group;
+ int enable_state;
- const int *groups;
+ const int *states;
} UiToggleArgs;
typedef struct UiLinkButtonArgs {
UiBool nofollow;
UiLinkType type;
- const int *groups;
+ const int *states;
} UiLinkButtonArgs;
#define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } )
int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
const char *name;
const char *style_class;
#define ui_left_panel0(obj) for(ui_left_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_right_panel0(obj) for(ui_right_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
-
#define ui_vbox_w(obj, w, ...) for(w = ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, &(UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_custom_container(ob, widget, addfunc, data) for(ui_custom_container_create(obj, widget, addfunc, data);ui_container_finish(obj);ui_container_begin_close(obj))
+
#define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, &(UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hsplitpane0(obj) for(ui_hsplitpane_create(obj, &(UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
UIEXPORT void ui_newline(UiObject *obj);
+typedef void(*ui_addwidget_func)(UiObject *obj, UIWIDGET parent, UIWIDGET child, void *userdata);
+UIEXPORT void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_func add_child, void *userdata);
+
// TODO
UIEXPORT UiTabbedPane* ui_tabbed_document_view(UiObject *obj);
UIEXPORT UiObject* ui_document_tab(UiTabbedPane *view);
ui_callback onchange;
void* onchangedata;
- const int *groups;
+ const int *states;
} UiSpinBoxArgs;
int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
const char *name;
const char *style_class;
typedef UiBool (*ui_list_savefunc)(UiList *list, int row, int col, UiCellValue *value, void *userdata);
+typedef void (*ui_model_update_func)(UiModel *model, void *userdata, int insert_index, int delete_index);
+
+typedef struct UiModelChangeObserver UiModelChangeObserver;
+struct UiModelChangeObserver {
+ ui_model_update_func update;
+ void *userdata;
+ UiModelChangeObserver *next;
+};
+
struct UiModel {
+ UiContext *ctx;
+
/*
* number of columns
*/
* array of column size hints
*/
int *columnsize;
+
+ /*
+ * Model change observers, that will be called when
+ * columns are added or removed
+ */
+ UiModelChangeObserver *observer;
+
+ /*
+ * reference counter
+ */
+ int ref;
};
struct UiListCallbacks {
const char *name;
const char *style_class;
- UiList* list;
+ UiList *list;
const char* varname;
- UiModel* model;
+ UiModel *model;
char **static_elements;
size_t static_nelm;
ui_getvaluefunc getvalue;
ui_getstylefunc getstyle;
void *getstyledata;
ui_callback onactivate;
- void* onactivatedata;
+ void *onactivatedata;
ui_callback onselection;
- void* onselectiondata;
+ void *onselectiondata;
ui_callback ondragstart;
- void* ondragstartdata;
+ void *ondragstartdata;
ui_callback ondragcomplete;
- void* ondragcompletedata;
+ void *ondragcompletedata;
ui_callback ondrop;
- void* ondropdata;
+ void *ondropdata;
UiBool multiselection;
UiMenuBuilder *contextmenu;
ui_list_savefunc onsave;
void *onsavedata;
- const int *groups;
+ const int *states;
};
typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata);
const char *name;
const char *style_class;
- const int *groups;
+ const int *states;
/*
* static list of sublists
*/
UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
UIEXPORT UiModel* ui_model_new(UiContext *ctx);
-UIEXPORT void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width);
+UIEXPORT void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width);
UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
-UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
+UIEXPORT void ui_model_ref(UiModel *model);
+UIEXPORT void ui_model_unref(UiModel *model);
+UIEXPORT void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data);
+UIEXPORT void ui_model_remove_observer(UiModel *model, void *data);
+UIEXPORT void ui_model_free(UiModel *mi);
#define ui_listview(obj, ...) ui_listview_create(obj, &(UiListArgs) { __VA_ARGS__ } )
#define ui_table(obj, ...) ui_table_create(obj, &(UiListArgs) { __VA_ARGS__ } )
-#define ui_combobox(obj, ...) ui_combobox_create(obj, &(UiListArgs) { __VA_ARGS__ } )
+#define ui_dropdown(obj, ...) ui_dropdown_create(obj, &(UiListArgs) { __VA_ARGS__ } )
#define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, &(UiListArgs) { __VA_ARGS__ } )
#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, &(UiSourceListArgs) { __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_listview_create(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_dropdown_create(UiObject *obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject *obj, UiListArgs *args);
UIEXPORT void ui_listview_select(UIWIDGET listview, int index);
-UIEXPORT void ui_combobox_select(UIWIDGET dropdown, int index);
+UIEXPORT void ui_dropdown_select(UIWIDGET dropdown, int index);
UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args);
ui_callback onclick;
void* onclickdata;
- const int* groups;
+ const int* states;
} UiMenuItemArgs;
typedef struct UiMenuToggleItemArgs {
ui_callback onchange;
void* onchangedata;
- const int* groups;
+ const int* nstates;
} UiMenuToggleItemArgs;
typedef struct UiMenuItemListArgs {
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef UI_STOCK_H
-#define UI_STOCK_H
-
-#include "toolkit.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// motif stock ids
-#if UI_MOTIF || UI_COCOA || UI_QT4 || UI_QT5
-
-#define UI_STOCK_NEW "ui.stock.New"
-#define UI_STOCK_OPEN "ui.stock.Open"
-#define UI_STOCK_SAVE "ui.stock.Save"
-#define UI_STOCK_SAVE_AS "ui.stock.SaveAs"
-#define UI_STOCK_REVERT_TO_SAVED "ui.stock.RevertToSaved"
-#define UI_STOCK_GO_BACK "ui.stock.GoBack"
-#define UI_STOCK_GO_FORWARD "ui.stock.GoForward"
-#define UI_STOCK_ADD "ui.stock.Add"
-#define UI_STOCK_CLOSE "ui.stock.Close"
-
-#define UI_STOCK_UNDO "ui.stock.Undo"
-#define UI_STOCK_REDO "ui.stock.Redo"
-#define UI_STOCK_CUT "ui.stock.Cut"
-#define UI_STOCK_COPY "ui.stock.Copy"
-#define UI_STOCK_PASTE "ui.stock.Paste"
-#define UI_STOCK_DELETE "ui.stock.Delete"
-
-#endif
-
-#if UI_GTK2 || UI_GTK3
-
-#define UI_STOCK_NEW GTK_STOCK_NEW
-#define UI_STOCK_OPEN GTK_STOCK_OPEN
-#define UI_STOCK_SAVE GTK_STOCK_SAVE
-#define UI_STOCK_SAVE_AS GTK_STOCK_SAVE_AS
-#define UI_STOCK_REVERT_TO_SAVED GTK_STOCK_REVERT_TO_SAVED
-#define UI_STOCK_UNDO GTK_STOCK_UNDO
-#define UI_STOCK_REDO GTK_STOCK_REDO
-#define UI_STOCK_GO_BACK GTK_STOCK_GO_BACK
-#define UI_STOCK_GO_FORWARD GTK_STOCK_GO_FORWARD
-#define UI_STOCK_ADD GTK_STOCK_ADD
-#define UI_STOCK_CLOSE GTK_STOCK_CLOSE
-
-#define UI_STOCK_UNDO GTK_STOCK_UNDO
-#define UI_STOCK_REDO GTK_STOCK_REDO
-#define UI_STOCK_CUT GTK_STOCK_CUT
-#define UI_STOCK_COPY GTK_STOCK_COPY
-#define UI_STOCK_PASTE GTK_STOCK_PASTE
-#define UI_STOCK_DELETE GTK_STOCK_DELETE
-
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UI_STOCK_H */
-
ui_callback onchange;
void *onchangedata;
- const int *groups;
+ const int *states;
} UiTextAreaArgs;
typedef struct UiTextFieldArgs {
ui_callback onactivate;
void *onactivatedata;
- const int *groups;
+ const int *states;
} UiTextFieldArgs;
typedef struct UiPathElmRet {
int margin_bottom;
int colspan;
int rowspan;
+ int width;
const char *name;
const char *style_class;
ui_callback onclick;
void* onclickdata;
- const int *groups;
+ const int *states;
const int *visibility_states;
} UiToolbarItemArgs;
ui_callback onchange;
void *onchangedata;
- const int *groups;
+ const int *states;
const int *visibility_states;
} UiToolbarToggleItemArgs;
#endif
+#elif UI_SERVER
+
+typedef struct UiWidget UiWidget;
+
+#define UIWIDGET UiWidget*
+#define UIWINDOW UiWidget*
+#define UIMENU void*
+
#endif
#ifndef TRUE
};
typedef void (*ui_list_init_func)(UiContext *ctx, UiList *list, void *userdata);
+typedef void (*ui_list_destroy_func)(UiContext *ctx, UiList *list, void *userdata);
/*
* abstract list
UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
UIEXPORT void ui_main(void);
+UIEXPORT void ui_app_quit(void);
UIEXPORT void ui_show(UiObject *obj);
UIEXPORT void ui_close(UiObject *obj);
UIEXPORT UiContext* ui_document_context(void *doc);
+UIEXPORT void* ui_context_get_document(UiContext *ctx);
+UIEXPORT void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable);
UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
-UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
-UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups);
+UIEXPORT void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
+UIEXPORT void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates);
UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates);
-UIEXPORT void ui_set_group(UiContext *ctx, int group);
-UIEXPORT void ui_unset_group(UiContext *ctx, int group);
-UIEXPORT int* ui_active_groups(UiContext *ctx, int *ngroups);
+UIEXPORT void ui_set_state(UiContext *ctx, int state);
+UIEXPORT void ui_unset_state(UiContext *ctx, int state);
+UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates);
UIEXPORT void* ui_allocator(UiContext *ctx);
UIEXPORT void* ui_cx_mempool(UiContext *ctx);
UIEXPORT void ui_var_set_string(UiContext *ctx, const char *name, char *value);
UIEXPORT char* ui_var_get_string(UiContext *ctx, const char *name);
+UIEXPORT UiInteger* ui_get_int_var(UiContext *ctx, const char *name);
+UIEXPORT UiDouble* ui_get_double_var(UiContext *ctx, const char *name);
+UIEXPORT UiString* ui_get_string_var(UiContext *ctx, const char *name);
+UIEXPORT UiText* ui_get_text_var(UiContext *ctx, const char *name);
+UIEXPORT UiRange* ui_get_range_var(UiContext *ctx, const char *name);
+UIEXPORT UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name);
+
UIEXPORT UiObserver* ui_observer_new(ui_callback f, void *data);
UIEXPORT UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer);
UIEXPORT UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);
UIEXPORT UiList* ui_list_new(UiContext *ctx, const char *name);
UIEXPORT UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func init, void *userdata);
-UIEXPORT void ui_list_free(UiList *list);
+UIEXPORT void ui_list_free(UiContext *ctx, UiList *list);
UIEXPORT void* ui_list_first(UiList *list);
UIEXPORT void* ui_list_next(UiList *list);
UIEXPORT void* ui_list_get(UiList *list, int i);
UIEXPORT void ui_setop_enable(int set);
UIEXPORT int ui_get_setop(void);
+UIEXPORT void ui_onchange_events_enable(UiBool enable);
+UIEXPORT UiBool ui_onchange_events_is_enabled(void);
UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata);
+UIEXPORT void ui_global_list_destructor(ui_list_destroy_func func, void *userdata);
UIEXPORT void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list));
UIEXPORT void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list));
UIEXPORT void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i));
UIEXPORT void ui_list_class_set_data(UiList *list, void *data);
UIEXPORT void ui_list_class_set_iter(UiList *list, void *iter);
+UIEXPORT void ui_object_set(UiObject *obj, const char *key, void *data);
+UIEXPORT void* ui_object_get(UiObject *obj, const char *key);
+
#ifdef __cplusplus
}
#endif
#include "menu.h"
#include "toolbar.h"
#include "window.h"
-#include "stock.h"
#include "button.h"
#include "text.h"
#include "properties.h"
-#include "tree.h"
+#include "list.h"
#include "graphics.h"
#include "entry.h"
#include "range.h"
int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
const char *name;
const char *style_class;
UiGeneric *value;
const char *varname;
- const int* groups;
+ const int* states;
} UiWebviewArgs;
#define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
#elif defined(UI_WIN32)
typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
+#elif defined(UI_SERVER)
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
#endif
UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args);
};\r
\r
struct W32WidgetClass {\r
- void (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+ int (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
void (*show)(W32Widget *widget, BOOLEAN show);\r
void (*enable)(W32Widget *widget, BOOLEAN enable);\r
W32Size (*get_preferred_size)(W32Widget *widget);\r
const char *lbutton2;
const char *rbutton3;
const char *rbutton4;
- const int *lbutton1_groups;
- const int *lbutton2_groups;
- const int *rbutton3_groups;
- const int *rbutton4_groups;
+ const int *lbutton1_states;
+ const int *lbutton2_states;
+ const int *rbutton3_states;
+ const int *rbutton4_states;
int default_button;
int width;
int height;
void *onclickdata;
} UiDialogWindowArgs;
-UIEXPORT UiObject *ui_window(const char *title, void *window_data);
-UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data);
+UIEXPORT UiObject *ui_window(const char *title);
+UIEXPORT UiObject *ui_sidebar_window(const char *title);
UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar);
-UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data);
+UIEXPORT UiObject *ui_simple_window(const char *title);
UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args);
#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ __VA_ARGS__ });
UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
UIEXPORT void ui_window_default_size(int width, int height);
+UIEXPORT void ui_window_menubar_set_visible(UiObject *obj, UiBool visible);
+
+UIEXPORT void ui_window_fullscreen(UiObject *obj, UiBool fullscreen);
UIEXPORT void ui_splitview_window_set_pos(UiObject *obj, int pos);
UIEXPORT int ui_splitview_window_get_pos(UiObject *obj);