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