From: Olaf Wintermann Date: Sun, 25 Jan 2026 11:11:59 +0000 (+0100) Subject: simplify list selections in nbconfig.c X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=85dae3939702e6dafd53c8d1ff28a8be8f780612;p=note.git simplify list selections in nbconfig.c --- diff --git a/application/nbconfig.c b/application/nbconfig.c index 792b286..ce68838 100644 --- a/application/nbconfig.c +++ b/application/nbconfig.c @@ -178,15 +178,11 @@ void nbconfig_notebook_save(NotebookConfigDialog *nbconfig) { // update parent int64_t prev_parent_id = res->parent_id; if(res->parent_id != nbconfig->root_resource_id) { - UiListSelection sel = ui_list_getselection(nbconfig->tab1_groups); - if(sel.count == 0) { - return; // shouldn't happen, maybe remove this when ui_list_getselectedindex exists - } - Resource *parent = ui_list_get(nbconfig->tab1_groups, sel.rows[0]); + int sel = ui_list_getselection(nbconfig->tab1_groups); + Resource *parent = ui_list_get(nbconfig->tab1_groups, sel); if(!parent) { return; //shouldn't happen } - ui_listselection_free(sel); prev_parent_id = res->parent_id; res->parent_id = parent->resource_id; } @@ -393,13 +389,12 @@ static void nbconfig_notebooklist_delete(UiEvent *event, void *userdata) { NotebookConfigDialog *wdata = event->window; NoteStore *store = note_store_get(); - UiListSelection sel = ui_list_getselection(wdata->tab1_notebooks); - if(sel.count == 1) { + int sel = ui_list_getselection(wdata->tab1_notebooks); + if(sel >= 0) { CxList *list = wdata->notebooks; - Resource *delete_res = cxListAt(list, sel.rows[0]); + Resource *delete_res = cxListAt(list, sel); note_store_collection_get_size_async(event->obj, delete_res, notebook_count_children_result, delete_res); } - ui_listselection_free(sel); } Resource* nbconfig_notebooklist_find_prev(NotebookConfigDialog *wdata, Resource *res) { @@ -452,9 +447,7 @@ static void nbconfig_notebooklist_move_up(UiEvent *event, void *userdata) { size_t res_index = cxListFind(nblist, wdata->selected_notebook); cxListSwap(nblist, prev_index, res_index); ui_list_update(wdata->tab1_notebooks); - wdata->valuechange = TRUE; - ui_list_setselection(wdata->tab1_notebooks, prev_index); - wdata->valuechange = FALSE; + ui_list_setselection2(wdata->tab1_notebooks, prev_index, FALSE); } } @@ -475,9 +468,7 @@ static void nbconfig_notebooklist_move_down(UiEvent *event, void *userdata) { size_t res_index = cxListFind(nblist, wdata->selected_notebook); cxListSwap(nblist, next_index, res_index); ui_list_update(wdata->tab1_notebooks); - wdata->valuechange = TRUE; - ui_list_setselection(wdata->tab1_notebooks, next_index); - wdata->valuechange = FALSE; + ui_list_setselection2(wdata->tab1_notebooks, next_index, FALSE); } } @@ -679,9 +670,7 @@ void notebook_config_dialog(void) { } } - wdata->valuechange = TRUE; - ui_list_setselection(wdata->tab1_notebooks, 0); - wdata->valuechange = FALSE; + ui_list_setselection2(wdata->tab1_notebooks, 0, FALSE); if(group1) { nbconfig_load_notebook(wdata, group1); diff --git a/application/window.c b/application/window.c index 53cc0f3..ba35fb9 100644 --- a/application/window.c +++ b/application/window.c @@ -307,13 +307,8 @@ static void action_nnd_button(UiEvent *event, void *userdata) { // add NoteStore *store = note_store_get(); - UiListSelection sel = ui_list_getselection(wdata->groups); - if(sel.count == 0) { - fprintf(stderr, "Error: no group selected\n"); - return; // TODO: error - } - Resource *parent = ui_list_get(wdata->groups, sel.rows[0]); - ui_listselection_free(sel); + int sel = ui_list_getselection(wdata->groups); + Resource *parent = ui_list_get(wdata->groups, sel); if(!parent) { fprintf(stderr, "Error: no parent found\n"); diff --git a/ui/cocoa/ListDelegate.m b/ui/cocoa/ListDelegate.m index 7e15f3d..9d80a7a 100644 --- a/ui/cocoa/ListDelegate.m +++ b/ui/cocoa/ListDelegate.m @@ -59,7 +59,7 @@ } - (void) tableViewSelectionDidChange:(NSNotification *) notification { - if(_onselection) { + if(_onselection && ui_selection_events_is_enabled()) { UiListSelection sel = ui_tableview_selection(_tableview); UiEvent event; diff --git a/ui/cocoa/list.m b/ui/cocoa/list.m index 5e72e92..97e9e4e 100644 --- a/ui/cocoa/list.m +++ b/ui/cocoa/list.m @@ -263,7 +263,7 @@ void ui_tableview_setselection(UiList *list, UiListSelection selection) { event.eventdatatype = UI_EVENT_DATA_LIST_ELM; event.intval = index; - if(_onselection) { + if(_onselection && ui_selection_events_is_enabled()) { _onselection(&event, _onselectiondata); } diff --git a/ui/common/types.c b/ui/common/types.c index 2f65c16..32cb180 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -153,7 +153,7 @@ void* ui_list_next(UiList *list) { } void* ui_list_get(UiList *list, int i) { - return cxListAt(list->data, i); + return i >= 0 ? cxListAt(list->data, i) : NULL; } int ui_list_count(UiList *list) { @@ -169,7 +169,9 @@ void ui_list_prepend(UiList *list, void *data) { } void ui_list_remove(UiList *list, int i) { - cxListRemove(list->data, i); + if(i >= 0) { + cxListRemove(list->data, i); + } } void ui_list_clear(UiList *list) { @@ -196,6 +198,12 @@ UiListSelection ui_list_get_selection(UiList *list) { } } +UIEXPORT void ui_list_set_selection(UiList *list, UiListSelection sel) { + if(list->setselection) { + list->setselection(list, sel); + } +} + void ui_list_addobsv(UiList *list, ui_callback f, void *data) { list->observers = ui_add_observer(list->observers, f, data); } @@ -789,21 +797,35 @@ void uic_generic_unbind(UiGeneric *g) { } -UIEXPORT UiListSelection ui_list_getselection(UiList *list) { +UIEXPORT int ui_list_getselection(UiList *list) { + int selection = -1; if (list->getselection) { - return list->getselection(list); + UiListSelection sel = list->getselection(list); + if(sel.count > 0) { + selection = sel.rows[0]; + } + ui_listselection_free(sel); } - return (UiListSelection){ 0, NULL }; + return selection; } UIEXPORT void ui_list_setselection(UiList *list, int index) { + ui_list_setselection2(list, index, TRUE); +} + +UIEXPORT void ui_list_setselection2(UiList *list, int index, UiBool selection_event) { if (list->setselection) { UiListSelection sel = { 0, NULL }; if(index >= 0) { sel.count = 1; sel.rows = &index; } + UiBool events = ui_selection_events_is_enabled(); + if(!selection_event) { + ui_selection_events_enable(FALSE); + } list->setselection(list, sel); + ui_selection_events_enable(events); } } @@ -870,6 +892,7 @@ void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObser static int ui_set_op = 0; static int ui_onchange_events_enabled = TRUE; +static int ui_selection_events_enabled = TRUE; void ui_setop_enable(int set) { ui_set_op = set; @@ -887,6 +910,14 @@ UiBool ui_onchange_events_is_enabled(void) { return ui_onchange_events_enabled; } +void ui_selection_events_enable(UiBool enable) { + ui_selection_events_enabled = enable; +} + +UiBool ui_selection_events_is_enabled(void) { + return ui_selection_events_enabled; +} + /* ---------------- List initializers and wrapper functions ---------------- */ void ui_global_list_initializer(ui_list_init_func func, void *userdata) { 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/gtk/list.c b/ui/gtk/list.c index 3914bf2..f3a3895 100644 --- a/ui/gtk/list.c +++ b/ui/gtk/list.c @@ -874,7 +874,9 @@ void ui_columnview_activate(void *ignore, guint position, gpointer userdata) { void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) { UiListView *view = userdata; listview_update_selection(view); - listview_event(view->onselection, view->onselectiondata, view); + if(ui_selection_events_is_enabled()) { + listview_event(view->onselection, view->onselectiondata, view); + } } void ui_dropdown_activate(GtkDropDown* self, gpointer userdata) { @@ -1795,6 +1797,10 @@ void ui_listview_selection_event( GtkTreeSelection *treeselection, UiTreeEventData *event) { + if(!ui_selection_events_is_enabled()) { + return; + } + UiListSelection selection = ui_listview_get_selection(treeselection, event); UiEvent e; diff --git a/ui/qt/list.cpp b/ui/qt/list.cpp index a2bac52..899e8c6 100644 --- a/ui/qt/list.cpp +++ b/ui/qt/list.cpp @@ -102,6 +102,9 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { if(args->multiselection) { view->setSelectionMode(QAbstractItemView::ExtendedSelection); } + if(args->hide_header) { + view->setHeaderHidden(true); + } UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); diff --git a/ui/qt/model.cpp b/ui/qt/model.cpp index 361da2f..c74c43f 100644 --- a/ui/qt/model.cpp +++ b/ui/qt/model.cpp @@ -99,6 +99,10 @@ QVariant ListModel::data(const QModelIndex &index, int role) const { } void ListModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { + if(!ui_selection_events_is_enabled()) { + return; + } + UiListSelection sel; if(listview) { sel = ui_selection_model_to_selection(listview->selectionModel()); diff --git a/ui/server/Makefile b/ui/server/Makefile new file mode 100644 index 0000000..7efd7f6 --- /dev/null +++ b/ui/server/Makefile @@ -0,0 +1,36 @@ +# +# 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. +# + +$(SERVER_OBJPRE)%.o: server/%.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 diff --git a/ui/server/args.c b/ui/server/args.c new file mode 100644 index 0000000..8257780 --- /dev/null +++ b/ui/server/args.c @@ -0,0 +1,57 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "args.h" + +#include + +#include "toolkit.h" +#include "../common/utils.h" + +void ui_argstr_add_int(CxBuffer *buf, const char *name, int i) { + char n[32]; + snprintf(n, 32, "%i", i); + + cxBufferPutString(buf, "\""); + cxBufferPutString(buf, name); + cxBufferPutString(buf, "\":"); + cxBufferPutString(buf, n); + cxBufferPutString(buf, ","); +} + +void ui_argstr_add_str(CxBuffer *buf, const char *name, const char *value) { + cxmutstr value_escaped = ui_escape_string(cx_str(value)); + cxBufferPutString(buf, "\""); + cxBufferPutString(buf, name); + cxBufferPutString(buf, "\":\""); + cxBufferPutString(buf, value_escaped.ptr); + cxBufferPutString(buf, "\","); + if(value != value_escaped.ptr) { + free(value_escaped.ptr); + } +} diff --git a/ui/server/args.h b/ui/server/args.h new file mode 100644 index 0000000..d421e9a --- /dev/null +++ b/ui/server/args.h @@ -0,0 +1,74 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ARGS_H +#define ARGS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void ui_argstr_add_int(CxBuffer *buf, const char *name, int i); +void ui_argstr_add_str(CxBuffer *buf, const char *name, const char *value); + +#define UI_STANDARD_ARGS(buf, args) \ + if(args->fill) cxBufferPutString(buf, "\"fill\":true,"); \ + if(args->hexpand) cxBufferPutString(buf, "\"hexpand\":true,"); \ + if(args->vexpand) cxBufferPutString(buf, "\"vexpand\":true,"); \ + if(args->hfill) cxBufferPutString(buf, "\"hfill\":true,"); \ + if(args->vfill) cxBufferPutString(buf, "\"vfill\":true,"); \ + if(args->override_defaults) cxBufferPutString(buf, "\"override_defaults\":true,"); \ + if(args->margin != 0) ui_argstr_add_int(buf, "margin", args->margin); \ + if(args->margin_left != 0) ui_argstr_add_int(buf, "margin_left", args->margin_left); \ + if(args->margin_right != 0) ui_argstr_add_int(buf, "margin_right", args->margin_right); \ + if(args->margin_top != 0) ui_argstr_add_int(buf, "margin_top", args->margin_top); \ + if(args->margin_bottom != 0) ui_argstr_add_int(buf, "margin_bottom", args->margin_bottom); \ + if(args->colspan != 0) ui_argstr_add_int(buf, "colspan", args->colspan); \ + if(args->rowspan != 0) ui_argstr_add_int(buf, "rowspan", args->rowspan); \ + if(args->name) ui_argstr_add_str(buf, "name", args->name); \ + if(args->style_class) ui_argstr_add_str(buf, "style_class", args->style_class) + +#define UI_LABEL_ARGS(buf, args) \ + if(args->label) ui_argstr_add_str(buf, "label", args->label); \ + if(args->icon) ui_argstr_add_str(buf, "icon", args->icon); \ + if(args->tooltip) ui_argstr_add_str(buf, "tooltip", args->tooltip) + +#define UI_SPACING_ARGS(buf, args) \ + if(args->spacing != 0) ui_argstr_add_int(buf, "spacing", args->spacing); \ + if(args->columnspacing != 0) ui_argstr_add_int(buf, "columnspacing", args->columnspacing); \ + if(args->rowspacing != 0) ui_argstr_add_int(buf, "rowspacing", args->rowspacing) + +#ifdef __cplusplus +} +#endif + +#endif /* ARGS_H */ + diff --git a/ui/server/button.c b/ui/server/button.c new file mode 100644 index 0000000..8182791 --- /dev/null +++ b/ui/server/button.c @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "button.h" +#include +#include + +#include "args.h" +#include "container.h" +#include "widget.h" +#include "var.h" + +cxmutstr ui_button_args_to_string(UiContext *ctx, UiButtonArgs *args) { + CxBuffer buf; + cxBufferInit(&buf, ctx->allocator, NULL, 256, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + + UI_STANDARD_ARGS(&buf, args); + UI_LABEL_ARGS(&buf, args); + if(args->labeltype != UI_LABEL_DEFAULT) ui_argstr_add_int(&buf, "labeltype", (int)args->labeltype); + + if(buf.size > 0 && buf.space[buf.size-1] == ',') { + buf.space[buf.size-1] = ' '; + } + cxBufferPutString(&buf, "}"); + return cx_mutstrn(buf.space, buf.size); +} + +cxmutstr ui_toggle_args_to_string(UiContext *ctx, UiToggleArgs *args, cxmutstr value) { + CxBuffer buf; + cxBufferInit(&buf, ctx->allocator, NULL, 256, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + + UI_STANDARD_ARGS(&buf, args); + UI_LABEL_ARGS(&buf, args); + if(value.ptr) ui_argstr_add_str(&buf, "value", value.ptr); + if(args->labeltype != UI_LABEL_DEFAULT) ui_argstr_add_int(&buf, "labeltype", (int)args->labeltype); + + if(buf.size > 0 && buf.space[buf.size-1] == ',') { + buf.space[buf.size-1] = ' '; + } + cxBufferPutString(&buf, "}"); + return cx_mutstrn(buf.space, buf.size); +} + + +UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) { + UiCallbackWidget *widget = cxZalloc(obj->ctx->allocator, sizeof(UiCallbackWidget)); + widget->widget.obj = obj->widget->obj; + widget->widget.type = cx_str("button"); + widget->widget.args = ui_button_args_to_string(obj->ctx, args); + widget->widget.serialize = (ui_serialize_func)ui_button_serialize; + widget->callback = args->onclick; + widget->userdata = args->onclickdata; + ui_reg_widget((UiWidget*)widget); + + UiWidget *parent = obj->container_end->container; + cxListAdd(parent->children, widget); + + return (UiWidget*)widget; +} + +cxmutstr ui_button_serialize(UiCallbackWidget *w) { + CxBuffer buf; + cxBufferInit(&buf, cxDefaultAllocator, NULL, 1024, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + ui_serialize_type_obj_id(&w->widget, &buf); + cxBufferPutString(&buf, ",\"args\":"); + cxBufferPutString(&buf, w->widget.args.ptr); + if(w->widget.var_id.ptr) { + cxBufferPutString(&buf, ",\"value\":\""); + cxBufferPutString(&buf, w->widget.var_id.ptr); + cxBufferPutString(&buf, "\""); + } + cxBufferPutString(&buf, "}\n"); + + return cx_mutstrn(buf.space, buf.size); +} + +static UIWIDGET togglebutton_create(UiObject *obj, const char *type, UiToggleArgs *args) { + cxmutstr var_id = cx_mutstrn(NULL, 0); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER); + if(var) { + UiInteger *i = var->value; + if(!i->obj) { + ui_server_bind_int(obj->ctx, i); + } + var_id = cx_mutstr(i->obj); + } + + UiCallbackWidget *widget = cxZalloc(obj->ctx->allocator, sizeof(UiCallbackWidget)); + widget->widget.obj = obj->widget->obj; + widget->widget.type = cx_str(type); + widget->widget.args = ui_toggle_args_to_string(obj->ctx, args, var_id); + widget->widget.var_id = var_id; + widget->widget.var_type = UI_VAR_INTEGER; + widget->widget.serialize = (ui_serialize_func)ui_button_serialize; + widget->callback = args->onchange; + widget->userdata = args->onchangedata; + ui_reg_widget((UiWidget*)widget); + + UiWidget *parent = obj->container_end->container; + cxListAdd(parent->children, widget); + + return (UiWidget*)widget; +} + +UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args) { + return togglebutton_create(obj, "togglebutton", args); +} + +UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args) { + return togglebutton_create(obj, "checkbox", args); +} + +UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args) { + return togglebutton_create(obj, "switch", args); +} + +UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { + return togglebutton_create(obj, "radiobutton", args); +} diff --git a/ui/server/button.h b/ui/server/button.h new file mode 100644 index 0000000..2b69389 --- /dev/null +++ b/ui/server/button.h @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BUTTON_H +#define BUTTON_H + +#include "toolkit.h" + +#include "../ui/button.h" + +#ifdef __cplusplus +extern "C" { +#endif + +cxmutstr ui_button_args_to_string(UiContext *ctx, UiButtonArgs *args); +cxmutstr ui_toggle_args_to_string(UiContext *ctx, UiToggleArgs *args, cxmutstr value); + +cxmutstr ui_button_serialize(UiCallbackWidget *w); + +#ifdef __cplusplus +} +#endif + +#endif /* BUTTON_H */ + diff --git a/ui/server/container.c b/ui/server/container.c new file mode 100644 index 0000000..17a64d4 --- /dev/null +++ b/ui/server/container.c @@ -0,0 +1,136 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "container.h" +#include "widget.h" +#include "args.h" + +void ui_container_begin_close(UiObject *obj) { + UiContainerX *ct = obj->container_end; + ct->close = 1; +} + +int ui_container_finish(UiObject *obj) { + UiContainerX *ct = obj->container_end; + if(ct->close) { + ui_end_new(obj); + return 0; + } + return 1; +} + +UiContainerX* ui_widget_container(UiWidget *w) { + UiContainerX *container = cxZalloc(w->obj->ctx->allocator, sizeof(UiContainerX)); + container->container = w; + return container; +} + +cxmutstr ui_container_args_to_string(UiContext *ctx, UiContainerArgs *args) { + CxBuffer buf; + cxBufferInit(&buf, ctx->allocator, NULL, 256, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + + UI_STANDARD_ARGS(&buf, args); + UI_SPACING_ARGS(&buf, args); + if(args->def_hfill) cxBufferPutString(&buf, "\"def_hfill\":true,"); + if(args->def_vfill) cxBufferPutString(&buf, "\"def_vfill\":true,"); + if(args->def_hexpand) cxBufferPutString(&buf, "\"def_hexpand\":true,"); + if(args->def_vexpand) cxBufferPutString(&buf, "\"def_vexpand\":true,"); + + if(buf.size > 0 && buf.space[buf.size-1] == ',') { + buf.space[buf.size-1] = ' '; + } + cxBufferPutString(&buf, "}"); + return cx_mutstrn(buf.space, buf.size); +} + +static UIWIDGET container_create(UiObject *obj, const char *type, UiContainerArgs *args) { + const CxAllocator *a = obj->ctx->allocator; + UiWidget *widget = cxZalloc(a, sizeof(UiWidget)); + widget->obj = obj->widget->obj; + widget->type = cx_str(type); + widget->args = ui_container_args_to_string(obj->ctx, args); + widget->children = cxLinkedListCreate(a, CX_STORE_POINTERS); + widget->serialize = ui_container_serialize; + + UiWidget *parent = obj->container_end->container; + cxListAdd(parent->children, widget); + + uic_object_push_container(obj, ui_widget_container(widget)); + ui_reg_widget((UiWidget*)widget); + + return widget; +} + +void ui_serialize_children(UiWidget *w, CxBuffer *buf) { + size_t numchildren = cxListSize(w->children); + if(numchildren > 0) { + cxBufferPutString(buf, ",\"children\":["); + CxIterator i = cxListIterator(w->children); + cx_foreach(UiWidget *, child, i) { + cxmutstr child_str = child->serialize(child); + cxBufferWrite(child_str.ptr, 1, child_str.length, buf); + if(i.index+1 < numchildren) { + cxBufferPut(buf, ','); + } + } + cxBufferPutString(buf, "]"); + } +} + +cxmutstr ui_container_serialize(UiWidget *w) { + CxBuffer buf; + cxBufferInit(&buf, cxDefaultAllocator, NULL, 1024, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + ui_serialize_type_obj_id(w, &buf); + cxBufferPutString(&buf, ",\"args\":"); + cxBufferPutString(&buf, w->args.ptr); + + ui_serialize_children(w, &buf); + + cxBufferPutString(&buf, "}\n"); + + return cx_mutstrn(buf.space, buf.size); +} + +UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { + return container_create(obj, "vbox", args); +} + +UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) { + return container_create(obj, "hbox", args); +} + +UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { + return container_create(obj, "grid", args); +} diff --git a/ui/server/container.h b/ui/server/container.h new file mode 100644 index 0000000..dc7f3e9 --- /dev/null +++ b/ui/server/container.h @@ -0,0 +1,54 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONTAINER_H +#define CONTAINER_H + +#include "toolkit.h" +#include "../common/container.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +UiContainerX* ui_widget_container(UiWidget *w); + +cxmutstr ui_container_args_to_string(UiContext *ctx, UiContainerArgs *args); + +void ui_serialize_children(UiWidget *w, CxBuffer *buf); + +cxmutstr ui_container_serialize(UiWidget *w); + +#ifdef __cplusplus +} +#endif + +#endif /* CONTAINER_H */ + diff --git a/ui/qt/stock.cpp b/ui/server/image.c similarity index 89% rename from ui/qt/stock.cpp rename to ui/server/image.c index 1ead20b..a54ebda 100644 --- a/ui/qt/stock.cpp +++ b/ui/server/image.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,10 +26,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "image.h" -#include "stock.h" -#include "../ui/properties.h" - - - +void ui_image_ref(UIIMAGE img) { + +} +void ui_image_unref(UIIMAGE img) { + +} diff --git a/ui/motif/stock.h b/ui/server/image.h similarity index 89% rename from ui/motif/stock.h rename to ui/server/image.h index c3cdb7f..2bc0490 100644 --- a/ui/motif/stock.h +++ b/ui/server/image.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,20 +26,21 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef STOCK_H -#define STOCK_H +#ifndef IMAGE_H +#define IMAGE_H -#include "../ui/stock.h" +#include "../ui/image.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif -#ifdef __cplusplus + +#ifdef __cplusplus } #endif -#endif /* STOCK_H */ +#endif /* IMAGE_H */ diff --git a/ui/server/objs.mk b/ui/server/objs.mk new file mode 100644 index 0000000..6d5fa31 --- /dev/null +++ b/ui/server/objs.mk @@ -0,0 +1,42 @@ +# +# 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. +# + +SERVER_SRC_DIR = ui/server/ +SERVER_OBJPRE = $(OBJ_DIR)$(SERVER_SRC_DIR) + +SERVEROBJ = toolkit.o +SERVEROBJ += widget.o +SERVEROBJ += args.o +SERVEROBJ += var.o +SERVEROBJ += window.o +SERVEROBJ += container.o +SERVEROBJ += button.o +SERVEROBJ += image.o + +TOOLKITOBJS += $(SERVEROBJ:%=$(SERVER_OBJPRE)%) +TOOLKITSOURCE += $(SERVEROBJ:%.o=SERVER/%.c) diff --git a/ui/server/toolkit.c b/ui/server/toolkit.c new file mode 100644 index 0000000..fd0b57d --- /dev/null +++ b/ui/server/toolkit.c @@ -0,0 +1,145 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "toolkit.h" + +#include "../common/message.h" +#include "../common/threadpool.h" +#include "../common/app.h" + +#include +#include + +static const char *ui_app_name; + +static UiMessageHandler *message_handler; + +static ui_callback onstartup; +static void *onstartupdata; + +static UiQueue *event_queue; + +static CxMap *srv_obj_map; +static uint64_t srv_obj_id_counter = 0; + +void ui_init(const char *appname, int argc, char **argv) { + ui_app_name = appname; + + message_handler = uic_simple_msg_handler(STDIN_FILENO, STDOUT_FILENO, ui_server_message_received); + + srv_obj_map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 16); +} + +const char* ui_appname() { + return ui_app_name; +} + +void ui_add_styledata(const char *styledata, int len) { + // NOOP +} + + +void ui_server_message_received(cxstring msg) { + +} + +void ui_main(void) { + uic_simple_msg_handler_start(message_handler); + uic_application_startup(NULL); + event_queue = ui_queue_create(); + UiServerEvent *event = NULL; + while((event = ui_queue_get_wait(event_queue)) != NULL) { + if(event->callback) { + event->callback(&event->event, event->userdata); + } + } + ui_queue_free(event_queue); +} + +typedef struct CallMain { + UiServerEvent event; + ui_threadfunc func; + void *data; +} CallMain; + +static void mainthr(UiServerEventData *event, void *userdata) { + CallMain *c = userdata; + if(c->func) { + c->func(c->data); + } + free(c); +} + +void ui_call_mainthread(ui_threadfunc tf, void* td) { + CallMain *c = malloc(sizeof(CallMain)); + c->func = tf; + c->data = td; + ui_queue_put(event_queue, c); +} + +void ui_show(UiObject *obj) { + if(!obj->widget->sent) { + cxmutstr msg = obj->widget->serialize(obj->widget); + obj->widget->sent = TRUE; + uic_message_send(message_handler, msg); + free(msg.ptr); + } + cxmutstr msg = cx_asprintf("{\"type\":\"show\", \"obj\":\"%s\"}\n", obj->widget->obj->id.ptr); + obj->widget->invisible = FALSE; + uic_message_send(message_handler, msg); + free(msg.ptr); +} + +UiSrvObj* ui_create_server_object(UiContext *ctx) { + const CxAllocator *a = ctx->allocator; + UiSrvObj *obj = cxZalloc(a, sizeof(UiSrvObj)); + + char id[32]; + snprintf(id, 32, "%" PRIx64, srv_obj_id_counter++); + obj->id = cx_strdup_a(a, id); + obj->ctx = ctx; + + obj->widgets = cxHashMapCreate(a, CX_STORE_POINTERS, 64); + + return obj; +} + +void ui_reg_widget(UiWidget *widget) { + UiSrvObj *obj = widget->obj; + + char id[32]; + snprintf(id, 32, "%" PRIx64, obj->widget_id_counter++); + + widget->id = cx_strdup_a(widget->obj->ctx->allocator, cx_str(id)); + cxMapPut(obj->widgets, id, widget); +} diff --git a/ui/server/toolkit.h b/ui/server/toolkit.h new file mode 100644 index 0000000..0a255a4 --- /dev/null +++ b/ui/server/toolkit.h @@ -0,0 +1,104 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TOOLKIT_H +#define TOOLKIT_H + +#include +#include "../ui/toolkit.h" +#include "../common/context.h" +#include "../common/object.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UiSrvObj UiSrvObj; + +typedef struct UiServerEvent UiServerEvent; +typedef struct UiServerEventData UiServerEventData; +typedef void(*ui_srvevent_func)(UiServerEventData *event, void *userdata); + +typedef cxmutstr (*ui_serialize_func)(UiWidget *w); + +struct UiServerEventData { + UiObject *obj; + cxmutstr str; + int intvalue; +}; + +struct UiServerEvent { + UiServerEventData event; + ui_srvevent_func callback; + void *userdata; +}; + +struct UiSrvObj { + UiContext *ctx; + cxmutstr id; + + CxMap *widgets; + uint64_t widget_id_counter; +}; + +struct UiWidget { + UiSrvObj *obj; + cxmutstr id; + cxstring type; + UiVar *var; + cxmutstr var_id; + UiVarType var_type; + CxList *children; + cxmutstr args; + UiBool invisible; + UiBool disabled; + UiBool sent; + ui_serialize_func serialize; +}; + +typedef struct UiCallbackWidget { + UiWidget widget; + ui_callback callback; + void *userdata; +} UiCallbackWidget; + +void ui_server_message_received(cxstring msg); + +UiSrvObj* ui_create_server_object(UiContext *ctx); +void ui_reg_widget(UiWidget *widget); + + +#ifdef __cplusplus +} +#endif + +#endif /* TOOLKIT_H */ + diff --git a/ui/server/var.c b/ui/server/var.c new file mode 100644 index 0000000..7865da2 --- /dev/null +++ b/ui/server/var.c @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "toolkit.h" + +#include "var.h" + +static uint64_t var_counter = 0; + +char* ui_generate_var_id(const CxAllocator *a) { + char id[32]; + snprintf(id, 32, "%" PRIx64, var_counter++); + return cx_strdup_a(a, id).ptr; +} + +cxmutstr ui_server_bind_int(UiContext *ctx, UiInteger *i) { + i->obj = ui_generate_var_id(ctx->allocator); + i->get = ui_server_int_get; + i->set = ui_server_int_set; + return cx_mutstr(i->obj); +} + +cxmutstr ui_server_bind_double(UiContext *ctx, UiDouble *d) { + d->obj = ui_generate_var_id(ctx->allocator); + d->get = ui_server_double_get; + d->set = ui_server_double_set; + return cx_mutstr(d->obj); +} + +cxmutstr ui_server_bind_string(UiContext *ctx, UiString *s) { + s->obj = ui_generate_var_id(ctx->allocator); + s->get = ui_server_string_get; + s->set = ui_server_string_set; + return cx_mutstr(s->obj); +} + + +int64_t ui_server_int_get(UiInteger *i) { + return 0; +} + +void ui_server_int_set(UiInteger *i, int64_t value) { + +} + +double ui_server_double_get(UiDouble *d) { + return 0; +} + +void ui_server_double_set(UiDouble *d, double value) { + +} + +char* ui_server_string_get(UiString *s) { + return NULL; +} + +void ui_server_string_set(UiString *s, const char *str) { + +} diff --git a/ui/server/var.h b/ui/server/var.h new file mode 100644 index 0000000..dd46dc6 --- /dev/null +++ b/ui/server/var.h @@ -0,0 +1,61 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VAR_H +#define VAR_H + +#include "../ui/toolkit.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +char* ui_generate_var_id(const CxAllocator *a); + +cxmutstr ui_server_bind_int(UiContext *ctx, UiInteger *i); +cxmutstr ui_server_bind_double(UiContext *ctx, UiDouble *d); +cxmutstr ui_server_bind_string(UiContext *ctx, UiString *s); + +int64_t ui_server_int_get(UiInteger *i); +void ui_server_int_set(UiInteger *i, int64_t value); + +double ui_server_double_get(UiDouble *d); +void ui_server_double_set(UiDouble *d, double value); + +char* ui_server_string_get(UiString *s); +void ui_server_string_set(UiString *s, const char *str); + + +#ifdef __cplusplus +} +#endif + +#endif /* VAR_H */ + diff --git a/ui/server/widget.c b/ui/server/widget.c new file mode 100644 index 0000000..01a15e3 --- /dev/null +++ b/ui/server/widget.c @@ -0,0 +1,51 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "widget.h" +#include "toolkit.h" + +void ui_serialize_type_obj_id(UiWidget *w, CxBuffer *buf) { + cxBufferPutString(buf, "\"type\":\""); + cxBufferPutString(buf, w->type.ptr); + cxBufferPutString(buf, "\",\"obj\":\""); + cxBufferPutString(buf, w->obj->id.ptr); + cxBufferPutString(buf, "\",\"id\":\""); + cxBufferPutString(buf, w->id.ptr); + cxBufferPutString(buf, "\""); +} + + +void ui_set_enabled(UIWIDGET widget, int enabled) { + +} + +void ui_set_visible(UIWIDGET widget, int visible) { + +} diff --git a/ui/qt/stock.h b/ui/server/widget.h similarity index 82% rename from ui/qt/stock.h rename to ui/server/widget.h index f80f1a4..66dce9e 100644 --- a/ui/qt/stock.h +++ b/ui/server/widget.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,12 +26,23 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef STOCK_H -#define STOCK_H +#ifndef WIDGET_H +#define WIDGET_H -#include "../ui/stock.h" +#include "../ui/widget.h" +#include +#ifdef __cplusplus +extern "C" { +#endif -#endif /* STOCK_H */ +void ui_serialize_type_obj_id(UiWidget *w, CxBuffer *buf); + + +#ifdef __cplusplus +} +#endif + +#endif /* WIDGET_H */ diff --git a/ui/server/window.c b/ui/server/window.c new file mode 100644 index 0000000..afc534c --- /dev/null +++ b/ui/server/window.c @@ -0,0 +1,93 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "window.h" +#include "container.h" +#include "widget.h" + +#include "../common/object.h" + +#include + +static UiObject* create_window(const char *title, const char *type, UiBool sidebar) { + UiObject *obj = uic_object_new_toplevel(); + const CxAllocator *a = obj->ctx->allocator; + + UiWindow *window = cxZalloc(a, sizeof(UiWindow)); + window->widget.obj = ui_create_server_object(obj->ctx); + window->widget.type = cx_str(type); + window->widget.children = cxLinkedListCreate(a, CX_STORE_POINTERS); + window->widget.serialize = (ui_serialize_func)ui_window_serialize; + window->widget.invisible = TRUE; + window->title = cx_strdup_a(a, title); + + obj->widget = (UiWidget*)window; + uic_object_push_container(obj, ui_widget_container((UiWidget*)window)); + ui_reg_widget(obj->widget); + + return obj; +} + +UiObject *ui_window(const char *title) { + return create_window(title, "window", FALSE); +} + +UiObject *ui_sidebar_window(const char *title) { + return create_window(title, "sidebar_window", FALSE); +} + +UiObject *ui_splitview_window(const char *title, UiBool sidebar) { + return create_window(title, "splitview_window", sidebar); +} + +UiObject *ui_simple_window(const char *title) { + return create_window(title, "simple_window", FALSE); +} + + +cxmutstr ui_window_serialize(UiWindow *w) { + CxBuffer buf; + cxBufferInit(&buf, NULL, NULL, 1024, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); + + cxBufferPutString(&buf, "{"); + ui_serialize_type_obj_id(&w->widget, &buf); + + if(w->title.ptr) { + cxBufferPutString(&buf, ",\"title\":\""); + cxBufferWrite(w->title.ptr, 1, w->title.length, &buf); + cxBufferPutString(&buf, "\""); + } + + ui_serialize_children(&w->widget, &buf); + + cxBufferPutString(&buf, "}\n"); + + return cx_mutstrn(buf.space, buf.size); +} + + diff --git a/ui/motif/stock.c b/ui/server/window.h similarity index 79% rename from ui/motif/stock.c rename to ui/server/window.h index 190fdbd..40191b9 100644 --- a/ui/motif/stock.c +++ b/ui/server/window.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,11 +26,27 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#ifndef WINDOW_H +#define WINDOW_H -#include "stock.h" -#include "../ui/properties.h" -#include +#include "../ui/window.h" +#include "toolkit.h" +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct UiWindow { + UiWidget widget; + cxmutstr title; +} UiWindow; + +cxmutstr ui_window_serialize(UiWindow *w); + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ diff --git a/ui/ui/stock.h b/ui/ui/stock.h deleted file mode 100644 index ab2d13d..0000000 --- a/ui/ui/stock.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UI_STOCK_H -#define UI_STOCK_H - -#include "toolkit.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// motif stock ids -#if UI_MOTIF || UI_COCOA || UI_QT4 || UI_QT5 - -#define UI_STOCK_NEW "ui.stock.New" -#define UI_STOCK_OPEN "ui.stock.Open" -#define UI_STOCK_SAVE "ui.stock.Save" -#define UI_STOCK_SAVE_AS "ui.stock.SaveAs" -#define UI_STOCK_REVERT_TO_SAVED "ui.stock.RevertToSaved" -#define UI_STOCK_GO_BACK "ui.stock.GoBack" -#define UI_STOCK_GO_FORWARD "ui.stock.GoForward" -#define UI_STOCK_ADD "ui.stock.Add" -#define UI_STOCK_CLOSE "ui.stock.Close" - -#define UI_STOCK_UNDO "ui.stock.Undo" -#define UI_STOCK_REDO "ui.stock.Redo" -#define UI_STOCK_CUT "ui.stock.Cut" -#define UI_STOCK_COPY "ui.stock.Copy" -#define UI_STOCK_PASTE "ui.stock.Paste" -#define UI_STOCK_DELETE "ui.stock.Delete" - -#endif - -#if UI_GTK2 || UI_GTK3 - -#define UI_STOCK_NEW GTK_STOCK_NEW -#define UI_STOCK_OPEN GTK_STOCK_OPEN -#define UI_STOCK_SAVE GTK_STOCK_SAVE -#define UI_STOCK_SAVE_AS GTK_STOCK_SAVE_AS -#define UI_STOCK_REVERT_TO_SAVED GTK_STOCK_REVERT_TO_SAVED -#define UI_STOCK_UNDO GTK_STOCK_UNDO -#define UI_STOCK_REDO GTK_STOCK_REDO -#define UI_STOCK_GO_BACK GTK_STOCK_GO_BACK -#define UI_STOCK_GO_FORWARD GTK_STOCK_GO_FORWARD -#define UI_STOCK_ADD GTK_STOCK_ADD -#define UI_STOCK_CLOSE GTK_STOCK_CLOSE - -#define UI_STOCK_UNDO GTK_STOCK_UNDO -#define UI_STOCK_REDO GTK_STOCK_REDO -#define UI_STOCK_CUT GTK_STOCK_CUT -#define UI_STOCK_COPY GTK_STOCK_COPY -#define UI_STOCK_PASTE GTK_STOCK_PASTE -#define UI_STOCK_DELETE GTK_STOCK_DELETE - -#endif - - -#ifdef __cplusplus -} -#endif - -#endif /* UI_STOCK_H */ - diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index fff2dda..9d23073 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -683,11 +683,15 @@ UIEXPORT void ui_list_clear(UiList *list); UIEXPORT void ui_list_update(UiList *list); UIEXPORT void ui_list_update_row(UiList *list, int row); 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 UiListSelection ui_list_getselection(UiList *list); +UIEXPORT int ui_list_getselection(UiList *list); UIEXPORT void ui_list_setselection(UiList *list, int index); +UIEXPORT void ui_list_setselection2(UiList *list, int index, UiBool selection_event); + +UIEXPORT void ui_listselection_free(UiListSelection selection); UIEXPORT UiFileList ui_filelist_copy(UiFileList list); UIEXPORT void ui_filelist_free(UiFileList list); @@ -699,9 +703,6 @@ UIEXPORT void ui_add_image(char *imgname, char *filename); // TODO: remove? -UIEXPORT void ui_listselection_free(UiListSelection selection); - - UIEXPORT UiStr ui_str(char *cstr); UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v)); @@ -719,6 +720,8 @@ UIEXPORT void ui_setop_enable(int set); UIEXPORT int ui_get_setop(void); UIEXPORT void ui_onchange_events_enable(UiBool enable); UIEXPORT UiBool ui_onchange_events_is_enabled(void); +UIEXPORT void ui_selection_events_enable(UiBool enable); +UIEXPORT UiBool ui_selection_events_is_enabled(void); UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata); diff --git a/ui/ui/tree.h b/ui/ui/tree.h deleted file mode 100644 index a71092b..0000000 --- a/ui/ui/tree.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UI_TREE_H -#define UI_TREE_H - -#include "toolkit.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct UiModel UiModel; -typedef struct UiListCallbacks UiListCallbacks; -typedef struct UiListDnd UiListDnd; - -typedef struct UiListArgs UiListArgs; -typedef struct UiSourceListArgs UiSourceListArgs; - -typedef struct UiSubList UiSubList; -typedef struct UiSubListItem UiSubListItem; - -typedef enum UiModelType { - UI_STRING = 0, - UI_STRING_FREE, - UI_INTEGER, - UI_ICON, - UI_ICON_TEXT, - UI_ICON_TEXT_FREE, - UI_STRING_EDITABLE, - UI_BOOL_EDITABLE -} UiModelType; - -typedef struct UiCellValue { - union { - const char *string; - int64_t i; - UiBool b; - }; - UiModelType type; -} UiCellValue; - -typedef UiBool (*ui_list_savefunc)(UiList *list, int row, int col, UiCellValue *value, void *userdata); - -struct UiModel { - /* - * number of columns - */ - int columns; - - /* - * current allocation size (internal) - */ - int alloc; - - /* - * array of column types - * array length is the number of columns - */ - UiModelType *types; - - /* - * array of column titles - * array length is the number of columns - */ - char **titles; - - /* - * array of column size hints - */ - int *columnsize; -}; - -struct UiListCallbacks { - /* - * selection callback - */ - ui_callback activate; - - /* - * cursor callback - */ - ui_callback selection; - - /* - * userdata for all callbacks - */ - void *userdata; -}; - -struct UiListArgs { - 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; - int width; - int height; - - const char *name; - const char *style_class; - UiList *list; - const char* varname; - UiModel *model; - char **static_elements; - size_t static_nelm; - ui_getvaluefunc getvalue; - ui_getvaluefunc2 getvalue2; - void *getvalue2data; - ui_getstylefunc getstyle; - void *getstyledata; - ui_callback onactivate; - void *onactivatedata; - ui_callback onselection; - void *onselectiondata; - ui_callback ondragstart; - void *ondragstartdata; - ui_callback ondragcomplete; - void *ondragcompletedata; - ui_callback ondrop; - void *ondropdata; - UiBool multiselection; - UiMenuBuilder *contextmenu; - ui_list_savefunc onsave; - void *onsavedata; - - const int *groups; -}; - -typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata); - -struct UiSubList { - UiList *value; - const char *varname; - const char *header; - UiBool separator; - void *userdata; -}; - -typedef struct UiSubListEventData { - UiList *list; - int sublist_index; - int row_index; - void *row_data; - void *sublist_userdata; - void *event_data; -} UiSubListEventData; - -/* - * list item members must be filled by the sublist getvalue func - * all members must be allocated (by malloc, strdup, ...) the pointer - * will be passed to free - */ -struct UiSubListItem { - char *icon; - char *label; - char *button_icon; - char *button_label; - UiMenuBuilder *button_menu; - char *badge; - void *eventdata; -}; - -struct UiSourceListArgs { - 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; - int width; - int height; - const char *name; - const char *style_class; - - const int *groups; - - /* - * static list of sublists - * a sublist must have a varname or a value - * - * the last entry in the list must contain all NULL values or numsublists - * must contain the number of sublists - * - * sublists can be NULL, in which case sublists are dynamically loaded - * from dynamic_sublist/varname - */ - UiSubList *sublists; - /* - * optional number of sublists - * if the value is 0, it is assumed, that sublists is null-terminated - * (last item contains only NULL values) - */ - size_t numsublists; - - /* - * list value, that contains UiSubList* elements - */ - UiList *dynamic_sublist; - - /* - * load sublists dynamically from a variable with the specified name - */ - const char *varname; - - - /* - * callback for each list item, that should fill all necessary - * UiSubListItem fields - */ - ui_sublist_getvalue_func getvalue; - - /* - * getvalue_func userdata - */ - void *getvaluedata; - - /* - * is a sublist header a selectable item - */ - UiBool header_is_item; - - /* - * activated when a list item is selected - */ - ui_callback onactivate; - void *onactivatedata; - - /* - * activated, when the additional list item button is clicked - */ - ui_callback onbuttonclick; - void *onbuttonclickdata; - - UiMenuBuilder *contextmenu; -}; - -#define UI_SUBLIST(...) (UiSubList){ __VA_ARGS__ } -#define UI_SUBLISTS(...) (UiSubList[]){ __VA_ARGS__, (UiSubList){NULL,NULL,NULL,0} } - - -/* - * Creates an UiModel, that specifies columns for a table widget. - * - * For each column a column type (UiModelType) and a title string - * (char*) must be specified. The column list must be terminated - * with -1. - * - * UiModel *model = ui_model(ctx, UI_STRING, "Column 1", UI_STRING, "Column 2", -1); - */ -UIEXPORT UiModel* ui_model(UiContext *ctx, ...); -UIEXPORT UiModel* ui_model_new(UiContext *ctx); -UIEXPORT void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width); -UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model); -UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi); - -#define ui_listview(obj, ...) ui_listview_create(obj, &(UiListArgs) { __VA_ARGS__ } ) -#define ui_table(obj, ...) ui_table_create(obj, &(UiListArgs) { __VA_ARGS__ } ) -#define ui_combobox(obj, ...) ui_combobox_create(obj, &(UiListArgs) { __VA_ARGS__ } ) -#define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, &(UiListArgs) { __VA_ARGS__ } ) -#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, &(UiSourceListArgs) { __VA_ARGS__ } ) - -UIEXPORT UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args); -UIEXPORT UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args); -UIEXPORT UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args); -UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject *obj, UiListArgs *args); - -UIEXPORT void ui_listview_select(UIWIDGET listview, int index); -UIEXPORT void ui_combobox_select(UIWIDGET dropdown, int index); - -UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args); - -UIEXPORT void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon); -UIEXPORT void ui_sublist_item_set_label(UiSubListItem *item, const char *label); -UIEXPORT void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon); -UIEXPORT void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label); -UIEXPORT void ui_sublist_item_set_button_menu(UiSubListItem *item, UiMenuBuilder *menu); -UIEXPORT void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge); -UIEXPORT void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata); - - - -/* - * Only relevant for some language bindings - */ -typedef void(*ui_sourcelist_update_func)(void); - -/* - * The sourcelist update callback is called after any source list - * sublist update is completed - */ -UIEXPORT void ui_sourcelist_set_update_callback(ui_sourcelist_update_func cb); - -#ifdef __cplusplus -} -#endif - -#endif /* UI_TREE_H */ - diff --git a/ui/win32/list.c b/ui/win32/list.c index b2c1495..179702a 100644 --- a/ui/win32/list.c +++ b/ui/win32/list.c @@ -41,7 +41,7 @@ static W32WidgetClass listview_widget_class = { .enable = w32_widget_default_enable, .show = w32_widget_default_show, .get_preferred_size = ui_listview_get_preferred_size, - .destroy = w32_widget_default_destroy + .destroy = ui_listview_destroy }; static void* strmodel_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { @@ -103,11 +103,15 @@ static UIWIDGET listview_create(UiObject *obj, UiListArgs *args, UiBool table) { HWND parent = ui_container_get_parent(container); UiLayout layout = UI_ARGS2LAYOUT(args); + unsigned int noheader = 0; + if (!table || args->hide_header) { + noheader = LVS_NOCOLUMNHEADER; + } HWND hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, WC_LISTVIEW, "", - WS_CHILD | WS_VISIBLE | LVS_REPORT, + WS_CHILD | WS_VISIBLE | LVS_REPORT | noheader, 0, 0, 100, 100, parent, (HMENU)1337, @@ -278,6 +282,14 @@ W32Size ui_listview_get_preferred_size(W32Widget *widget) { return size; } +void ui_listview_destroy(W32Widget *widget) { + UiListView *listview = (UiListView*)widget; + if (listview->model) { + ui_model_unref(listview->model); + } + free(widget); +} + /* * Creates and inserts an LVITEM * diff --git a/ui/win32/list.h b/ui/win32/list.h index 3074ed4..b8d501b 100644 --- a/ui/win32/list.h +++ b/ui/win32/list.h @@ -64,6 +64,7 @@ typedef struct UiListView { int ui_listview_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); W32Size ui_listview_get_preferred_size(W32Widget *widget); +void ui_listview_destroy(W32Widget *widget); void ui_listview_update(UiList *list, int row); UiListSelection ui_listview_getselection_impl(UiList *list);