# HG changeset patch # User Olaf Wintermann # Date 1707755522 -3600 # Node ID 3fc287f06305ed0d06d36c8a239f155a738cee58 # Parent 1ecc1183f046bb5c21c832e20e8c90dde8e1d7ea add minimal working download diff -r 1ecc1183f046 -r 3fc287f06305 application/application.c --- a/application/application.c Sun Feb 11 15:59:56 2024 +0100 +++ b/application/application.c Mon Feb 12 17:32:02 2024 +0100 @@ -88,7 +88,7 @@ ui_toolbar_item("NewFolder", .icon = "NewFolder", .onclick = action_mkcol); ui_toolbar_item("NewFile", .icon = "Add", .onclick = action_newfile); ui_toolbar_item("Upload", .label = "Upload", .icon = "Upload", .onclick = action_upload_file); - ui_toolbar_item("Download", .icon = "SaveLocal"); + ui_toolbar_item("Download", .icon = "SaveLocal", .onclick = action_download); ui_toolbar_item("Remove", .icon = "Delete", .onclick = action_delete ); ui_toolbar_toggleitem("LocalBrowser", .icon = "DockLeft", .label = "Local Browser"); ui_toolbar_toggleitem("PreviewPane", .icon = "DockRight"); @@ -175,6 +175,65 @@ } + + +static void download_location_selected(UiEvent *event, void *data) { + DavBrowser *browser = event->document; + DavResource *reslist = data; + UiFileList *flist = event->eventdata; + + if (flist && flist->nfiles > 0) { + davbrowser_download(event->obj, browser, reslist, flist->files[0]); + } else { + dav_session_destroy(reslist->session); + } +} + +void action_download(UiEvent *event, void *data) { + DavBrowser *browser = event->document; + UiListSelection sel = ui_list_getselection(browser->resources); + if (sel.count > 0) {; + const char *initialFileName = NULL; + if (sel.count == 1) { + DavResource *res = ui_list_get(browser->resources, sel.rows[0]); + if (res && !res->iscollection) { + initialFileName = res->name; + } + } + + // create a copy of the current session and all selected resources + DavSession *sn = dav_session_clone(browser->sn); + DavResource *first = NULL; + DavResource *last = NULL; + for (int i = 0; i < sel.count; i++) { + // get selected resource + DavResource *res = ui_list_get(browser->resources, sel.rows[i]); + // copy resource + DavResource *res_copy = dav_resource_new(sn, res->path); + res_copy->iscollection = res->iscollection; + res_copy->contentlength = res->contentlength; + res_copy->lastmodified = res->lastmodified; + res_copy->creationdate = res->creationdate; + + // link resources + if (!first) { + first = res_copy; + } + if (last) { + res_copy->prev = last; + last->next = res_copy; + } + last = res_copy; + } + + if (initialFileName) { + ui_savefiledialog(event->obj, initialFileName, download_location_selected, first); + } else { + ui_openfiledialog(event->obj, UI_FILEDIALOG_SELECT_FOLDER, download_location_selected, first); + } + } +} + void action_upload_file(UiEvent *event, void *data) { ui_openfiledialog(event->obj, UI_FILEDIALOG_SELECT_MULTI, file_selected, NULL); } diff -r 1ecc1183f046 -r 3fc287f06305 application/application.h --- a/application/application.h Sun Feb 11 15:59:56 2024 +0100 +++ b/application/application.h Mon Feb 12 17:32:02 2024 +0100 @@ -107,6 +107,8 @@ void action_repo_selected(UiEvent *event, void *data); +void action_download(UiEvent *event, void *data); + void action_upload_file(UiEvent *event, void *data); void action_delete(UiEvent *event, void *data); diff -r 1ecc1183f046 -r 3fc287f06305 application/davcontroller.c --- a/application/davcontroller.c Sun Feb 11 15:59:56 2024 +0100 +++ b/application/davcontroller.c Mon Feb 12 17:32:02 2024 +0100 @@ -666,6 +666,143 @@ } +// ------------------------------------- File Download ------------------------------------- + +typedef struct DavFileDownload { + UiObject *ui; + DavBrowser *browser; + + DavSession *sn; + DavResource *reslist; + char *local_path; + DavBool isdirectory; + + UiThreadpool *queue; + + size_t total_bytes; + size_t total_files; + size_t total_directories; + size_t downloaded_bytes; + size_t downloaded_files; + size_t downloaded_directories; + + UiObject *dialog; + UiDouble *progress; + UiString *label_top_left; + UiString *label_top_right; + UiString *label_bottom_left; + UiString *label_bottom_right; +} DavFileDownload; + +// dav download file +typedef struct DDFile { + DavFileDownload *download; + DavResource *res; + char *to; +} DDFile; + +static int qthr_download_resource(void *data) { + DDFile *file = data; + + FILE *f = fopen(file->to, "wb"); + if (!f) { + return 0; + } + + dav_get_content(file->res, f, (dav_write_func)fwrite); + + fclose(f); +} + +static int jobthr_download_scan(void *data) { + DavFileDownload *download = data; + DavBrowser *browser = download->browser; + + // check if the specified local location is a directory + SYS_STAT s; + if (!sys_stat(download->local_path, &s)) { + if (S_ISDIR(s.st_mode)) { + download->isdirectory = TRUE; + } + } + + // add selected files to the download queue + DavResource *res = download->reslist; + while (res) { + DDFile *file = malloc(sizeof(DDFile)); + file->download = download; + file->res = res; + if (download->isdirectory) { + file->to = util_concat_path(download->local_path, res->name); + } else { + file->to = strdup(download->local_path); + } + + ui_threadpool_job(download->queue, download->ui, qthr_download_resource, file, NULL, NULL); + + res = res->next; + } +} + +static void uithr_download_scan_finished(UiEvent *event, void *data) { + +} + +static void download_window_closed(UiEvent *event, void *data) { + +} + + +void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) { + DavFileDownload *download = malloc(sizeof(DavFileDownload)); + memset(download, 0, sizeof(DavFileDownload)); + + download->browser = browser; + download->sn = reslist->session; + download->reslist = reslist; + download->local_path = strdup(local_path); + + download->queue = ui_threadpool_create(1); + + // create download progress window + cxmutstr wtitle = cx_asprintf("Download to: %s", local_path); + UiObject *dialog = ui_simple_window(wtitle.ptr, download); + ui_context_closefunc(dialog->ctx, download_window_closed, NULL); + free(wtitle.ptr); + download->dialog = dialog; + ui_window_size(dialog, 550, 120); + download->progress = ui_double_new(dialog->ctx, NULL); + download->label_top_left = ui_string_new(dialog->ctx, NULL); + download->label_top_right = ui_string_new(dialog->ctx, NULL); + download->label_bottom_left = ui_string_new(dialog->ctx, NULL); + download->label_bottom_right = ui_string_new(dialog->ctx, NULL); + + ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) { + ui_llabel(dialog, .value = download->label_top_left, .hexpand = TRUE); + ui_rlabel(dialog, .value = download->label_top_right); + ui_newline(dialog); + + ui_progressbar(dialog, .value = download->progress, .colspan = 2, .hexpand = TRUE); + ui_newline(dialog); + + ui_llabel(dialog, .value = download->label_bottom_left); + ui_rlabel(dialog, .value = download->label_bottom_right); + ui_newline(dialog); + } + + ui_set(download->label_top_left, ""); + ui_set(download->label_top_right, ""); + ui_set(download->label_bottom_left, ""); + ui_set(download->label_bottom_right, ""); + ui_set(download->progress, 0); + + ui_show(dialog); + + // start upload and stat threads + ui_job(ui, jobthr_download_scan, download, uithr_download_scan_finished, download); +} + + // ------------------------------------- Path Operation (DELETE, MKCOL) ------------------------------------- enum DavPathOpType { @@ -812,8 +949,6 @@ return 0; } - - void davbrowser_delete(UiObject *ui, DavBrowser *browser, UiListSelection selection) { DavPathOp *op = malloc(sizeof(DavPathOp)); op->ui = ui; diff -r 1ecc1183f046 -r 3fc287f06305 application/davcontroller.h --- a/application/davcontroller.h Sun Feb 11 15:59:56 2024 +0100 +++ b/application/davcontroller.h Mon Feb 12 17:32:02 2024 +0100 @@ -58,6 +58,8 @@ void davbrowser_upload_files(UiObject *ui, DavBrowser *browser, UiFileList files); +void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path); + void davbrowser_delete(UiObject *ui, DavBrowser *browser, UiListSelection selection); void davbrowser_mkcol(UiObject *ui, DavBrowser *browser, const char *name); diff -r 1ecc1183f046 -r 3fc287f06305 ui/common/menu.c --- a/ui/common/menu.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/common/menu.c Mon Feb 12 17:32:02 2024 +0100 @@ -61,7 +61,7 @@ return s ? strdup(s) : NULL; } -static int* copy_groups(int* groups, size_t *ngroups) { +static int* copy_groups(const int* groups, size_t *ngroups) { *ngroups = 0; if (!groups) { return NULL; diff -r 1ecc1183f046 -r 3fc287f06305 ui/common/menu.h --- a/ui/common/menu.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/common/menu.h Mon Feb 12 17:32:02 2024 +0100 @@ -65,7 +65,7 @@ struct UiMenu { UiMenuItemI item; - char *label; + const char *label; UiMenuItemI *items_begin; UiMenuItemI *items_end; UiMenu *parent; diff -r 1ecc1183f046 -r 3fc287f06305 ui/common/objs.mk --- a/ui/common/objs.mk Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/common/objs.mk Mon Feb 12 17:32:02 2024 +0100 @@ -35,6 +35,8 @@ COMMON_OBJ += types.o COMMON_OBJ += menu.o COMMON_OBJ += properties.o +COMMON_OBJ += menu.o +COMMON_OBJ += toolbar.o COMMON_OBJ += ucx_properties.o TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)%) diff -r 1ecc1183f046 -r 3fc287f06305 ui/common/properties.c --- a/ui/common/properties.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/common/properties.c Mon Feb 12 17:32:02 2024 +0100 @@ -57,7 +57,7 @@ } char* ui_configfile(char *name) { - char *appname = ui_appname(); + const char *appname = ui_appname(); if(!appname) { return NULL; } diff -r 1ecc1183f046 -r 3fc287f06305 ui/common/toolbar.c --- a/ui/common/toolbar.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/common/toolbar.c Mon Feb 12 17:32:02 2024 +0100 @@ -37,108 +37,108 @@ static UiToolbarMenuItem* ui_appmenu; void uic_toolbar_init(void) { - toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - toolbar_defaults[0] = cxLinkedListCreateSimple(CX_STORE_POINTERS); - toolbar_defaults[1] = cxLinkedListCreateSimple(CX_STORE_POINTERS); - toolbar_defaults[2] = cxLinkedListCreateSimple(CX_STORE_POINTERS); + toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); + toolbar_defaults[0] = cxLinkedListCreateSimple(CX_STORE_POINTERS); + toolbar_defaults[1] = cxLinkedListCreateSimple(CX_STORE_POINTERS); + toolbar_defaults[2] = cxLinkedListCreateSimple(CX_STORE_POINTERS); } -static char* nl_strdup(char* str) { - return str ? strdup(str) : NULL; +static char* nl_strdup(const char* str) { + return str ? strdup(str) : NULL; } static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs args) { - UiToolbarItemArgs newargs; - newargs.label = nl_strdup(args.label); - newargs.stockid = nl_strdup(args.stockid); - newargs.icon = nl_strdup(args.icon); - newargs.onclick = args.onclick; - newargs.onclickdata = args.onclickdata; - return newargs; + UiToolbarItemArgs newargs; + newargs.label = nl_strdup(args.label); + newargs.stockid = nl_strdup(args.stockid); + newargs.icon = nl_strdup(args.icon); + newargs.onclick = args.onclick; + newargs.onclickdata = args.onclickdata; + return newargs; } void ui_toolbar_item_create(const char* name, UiToolbarItemArgs args) { - UiToolbarItem* item = malloc(sizeof(UiToolbarItem)); - item->item.type = UI_TOOLBAR_ITEM; - item->args = itemargs_copy(args); - cxMapPut(toolbar_items, name, item); + UiToolbarItem* item = malloc(sizeof(UiToolbarItem)); + item->item.type = UI_TOOLBAR_ITEM; + item->args = itemargs_copy(args); + cxMapPut(toolbar_items, name, item); } static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs args) { - UiToolbarToggleItemArgs newargs; - newargs.label = nl_strdup(args.label); - newargs.stockid = nl_strdup(args.stockid); - newargs.icon = nl_strdup(args.icon); - newargs.varname = nl_strdup(args.varname); - newargs.onchange = args.onchange; - newargs.onchangedata = args.onchangedata; - return newargs; + UiToolbarToggleItemArgs newargs; + newargs.label = nl_strdup(args.label); + newargs.stockid = nl_strdup(args.stockid); + newargs.icon = nl_strdup(args.icon); + newargs.varname = nl_strdup(args.varname); + newargs.onchange = args.onchange; + newargs.onchangedata = args.onchangedata; + return newargs; } void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs args) { - UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem)); - item->item.type = UI_TOOLBAR_TOGGLEITEM; - item->args = toggleitemargs_copy(args); - cxMapPut(toolbar_items, name, item); + UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem)); + item->item.type = UI_TOOLBAR_TOGGLEITEM; + item->args = toggleitemargs_copy(args); + cxMapPut(toolbar_items, name, item); } static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs args) { - UiToolbarMenuArgs newargs; - newargs.label = nl_strdup(args.label); - newargs.stockid = nl_strdup(args.stockid); - newargs.icon = nl_strdup(args.icon); - return newargs; + UiToolbarMenuArgs newargs; + newargs.label = nl_strdup(args.label); + newargs.stockid = nl_strdup(args.stockid); + newargs.icon = nl_strdup(args.icon); + return newargs; } UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs args) { - UiToolbarMenuItem* item = malloc(sizeof(UiToolbarMenuItem)); - item->item.type = UI_TOOLBAR_MENU; - memset(&item->menu, 0, sizeof(UiMenu)); - item->args = menuargs_copy(args); - - item->end = 0; + UiToolbarMenuItem* item = malloc(sizeof(UiToolbarMenuItem)); + item->item.type = UI_TOOLBAR_MENU; + memset(&item->menu, 0, sizeof(UiMenu)); + item->args = menuargs_copy(args); + + item->end = 0; - if (!name) { - // special appmenu - ui_appmenu = item; - } else { - // toplevel menu - cxMapPut(toolbar_items, name, item); - } + if (!name) { + // special appmenu + ui_appmenu = item; + } else { + // toplevel menu + cxMapPut(toolbar_items, name, item); + } - uic_add_menu_to_stack(&item->menu); + uic_add_menu_to_stack(&item->menu); } CxMap* uic_get_toolbar_items(void) { - return toolbar_items; + return toolbar_items; } CxList* uic_get_toolbar_defaults(enum UiToolbarPos pos) { - if (pos >= 0 && pos < 3) { - return toolbar_defaults[pos]; - } + if (pos >= 0 && pos < 3) { + return toolbar_defaults[pos]; + } + return NULL; } void ui_toolbar_add_default(const char* name, enum UiToolbarPos pos) { - char* cp = strdup(name); - if (pos >= 0 && pos < 3) { - cxListAdd(toolbar_defaults[pos], cp); - } - else { - // TODO: error - } + char* cp = strdup(name); + if (pos >= 0 && pos < 3) { + cxListAdd(toolbar_defaults[pos], cp); + } else { + // TODO: error + } } UiBool uic_toolbar_isenabled(void) { - return toolbar_defaults[0]->size + toolbar_defaults[1]->size + toolbar_defaults[2]->size > 0; + return toolbar_defaults[0]->size + toolbar_defaults[1]->size + toolbar_defaults[2]->size > 0; } UiToolbarItemI* uic_toolbar_get_item(const char* name) { - return cxMapGet(toolbar_items, name); + return cxMapGet(toolbar_items, name); } UiToolbarMenuItem* uic_get_appmenu(void) { - return ui_appmenu; + return ui_appmenu; } diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/button.c --- a/ui/gtk/button.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/button.c Mon Feb 12 17:32:02 2024 +0100 @@ -35,7 +35,7 @@ #include "../common/context.h" #include "../common/object.h" -UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { +UIWIDGET ui_button_deprecated(UiObject *obj, char *label, ui_callback f, void *data) { GtkWidget *button = gtk_button_new_with_label(label); if(f) { @@ -132,7 +132,7 @@ return button; } -UIWIDGET ui_checkbox(UiObject *obj, char *label, UiInteger *value) { +UIWIDGET ui_checkbox_deprecated(UiObject *obj, char *label, UiInteger *value) { UiVar *var = NULL; if(value) { var = malloc(sizeof(UiVar)); @@ -190,7 +190,7 @@ return rbutton; } -UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { +UIWIDGET ui_radiobutton_deprecated(UiObject *obj, char *label, UiInteger *rgroup) { UiVar *var = NULL; if(rgroup) { var = malloc(sizeof(UiVar)); diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/container.c --- a/ui/gtk/container.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/container.c Mon Feb 12 17:32:02 2024 +0100 @@ -67,22 +67,6 @@ #endif } -/* -------------------- Frame Container (deprecated) -------------------- */ -UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) { - UiContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct->widget = frame; - ct->add = ui_frame_container_add; - return ct; -} - -void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { - gtk_container_add(GTK_CONTAINER(ct->widget), widget); - ui_reset_layout(ct->layout); - ct->current = widget; -} /* -------------------- Box Container -------------------- */ @@ -243,13 +227,6 @@ } -UIWIDGET ui_vbox(UiObject *obj) { - return ui_vbox_sp(obj, 0, 0); -} - -UIWIDGET ui_hbox(UiObject *obj) { - return ui_hbox_sp(obj, 0, 0); -} static GtkWidget* box_set_margin(GtkWidget *box, int margin) { GtkWidget *ret = box; @@ -272,11 +249,13 @@ return ret; } -UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { - UiContainer *ct = uic_get_current_container(obj); +UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) { + UiObject *current = uic_current_obj(obj); + UiContainer *ct = current->container; + UI_APPLY_LAYOUT1(current, args); - GtkWidget *vbox = ui_gtk_vbox_new(spacing); - GtkWidget *widget = margin > 0 ? box_set_margin(vbox, margin) : vbox; + GtkWidget *vbox = ui_gtk_vbox_new(args.spacing); + GtkWidget *widget = args.margin > 0 ? box_set_margin(vbox, args.margin) : vbox; ct->add(ct, widget, TRUE); UiObject *newobj = uic_object_new(obj, vbox); @@ -286,41 +265,33 @@ return widget; } -UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { - UiContainer *ct = uic_get_current_container(obj); - - GtkWidget *hbox = ui_gtk_hbox_new(spacing); - GtkWidget *widget = margin > 0 ? box_set_margin(hbox, margin) : hbox; - ct->add(ct, widget, TRUE); - - UiObject *newobj = uic_object_new(obj, hbox); - newobj->container = ui_box_container(obj, hbox); - uic_obj_add(obj, newobj); - - return widget; +UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box_create(obj, args, UI_CONTAINER_VBOX); } -UIWIDGET ui_grid(UiObject *obj) { - return ui_grid_sp(obj, 0, 0, 0); +UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box_create(obj, args, UI_CONTAINER_HBOX); } -UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { + + +UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { UiContainer *ct = uic_get_current_container(obj); GtkWidget *widget; #ifdef UI_GTK3 GtkWidget *grid = gtk_grid_new(); - gtk_grid_set_column_spacing(GTK_GRID(grid), columnspacing); - gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing); + gtk_grid_set_column_spacing(GTK_GRID(grid), args.columnspacing); + gtk_grid_set_row_spacing(GTK_GRID(grid), args.rowspacing); #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 - gtk_widget_set_margin_start(grid, margin); - gtk_widget_set_margin_end(grid, margin); + gtk_widget_set_margin_start(grid, args.margin); + gtk_widget_set_margin_end(grid, args.margin); #else gtk_widget_set_margin_left(grid, margin); gtk_widget_set_margin_right(grid, margin); #endif - gtk_widget_set_margin_top(grid, margin); - gtk_widget_set_margin_bottom(grid, margin); + gtk_widget_set_margin_top(grid, args.margin); + gtk_widget_set_margin_bottom(grid, args.margin); widget = grid; #elif defined(UI_GTK2) @@ -347,38 +318,6 @@ return widget; } -UIWIDGET ui_scrolledwindow(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); - ct->add(ct, sw, TRUE); - - UiObject *newobj = uic_object_new(obj, sw); - newobj->container = ui_scrolledwindow_container(obj, sw); - uic_obj_add(obj, newobj); - - return sw; -} - -UIWIDGET ui_tabview(UiObject *obj) { - GtkWidget *tabview = gtk_notebook_new(); - gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(tabview), FALSE); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, tabview, TRUE); - - UiObject *tabviewobj = uic_object_new(obj, tabview); - tabviewobj->container = ui_tabview_container(obj, tabview); - uic_obj_add(obj, tabviewobj); - - return tabview; -} - -void ui_tab(UiObject *obj, char *title) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.label = title; - ui_vbox(obj); -} void ui_select_tab(UIWIDGET tabview, int tab) { gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); @@ -401,192 +340,9 @@ return NULL; } -UIWIDGET ui_splitpane(UiObject *obj, int max, UiOrientation orientation) { - GtkWidget *paned = create_paned(orientation); - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, paned, TRUE); - - if(max <= 0) max = INT_MAX; - - UiPanedContainer *pctn = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiPanedContainer)); - pctn->container.widget = paned; - pctn->container.add = ui_paned_container_add; - pctn->current_pane = paned; - pctn->orientation = orientation; - pctn->max = max; - pctn->cur = 0; - - UiObject *pobj = uic_object_new(obj, paned); - pobj->container = (UiContainer*)pctn; - - uic_obj_add(obj, pobj); - - return paned; -} - -UIWIDGET ui_hsplitpane(UiObject *obj, int max) { - return ui_splitpane(obj, max, UI_HORIZONTAL); -} - -UIWIDGET ui_vsplitpane(UiObject *obj, int max) { - return ui_splitpane(obj, max, UI_VERTICAL); -} - -void ui_paned_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { - UiPanedContainer *pctn = (UiPanedContainer*)ct; - - gboolean resize = (ct->layout.hexpand || ct->layout.vexpand) ? TRUE : FALSE; - int width = ct->layout.width; - ui_reset_layout(ct->layout); - - if(pctn->cur == 0) { - gtk_paned_pack1(GTK_PANED(pctn->current_pane), widget, resize, resize); - } else if(pctn->cur < pctn->max-1) { - GtkWidget *nextPane = create_paned(pctn->orientation); - gtk_paned_pack2(GTK_PANED(pctn->current_pane), nextPane, TRUE, TRUE); - gtk_paned_pack1(GTK_PANED(nextPane), widget, resize, resize); - pctn->current_pane = nextPane; - } else if(pctn->cur == pctn->max-1) { - gtk_paned_pack2(GTK_PANED(pctn->current_pane), widget, resize, resize); - width = 0; // disable potential call of gtk_paned_set_position - } else { - fprintf(stderr, "Splitpane max reached: %d\n", pctn->max); - return; - } - - if(width > 0) { - gtk_paned_set_position(GTK_PANED(pctn->current_pane), width); - } - - pctn->cur++; -} -/* -------------------- Sidebar (deprecated) -------------------- */ -UIWIDGET ui_sidebar(UiObject *obj) { -#ifdef UI_GTK3 - GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); -#else - GtkWidget *paned = gtk_hpaned_new(); -#endif - gtk_paned_set_position(GTK_PANED(paned), 200); - - GtkWidget *sidebar = ui_gtk_vbox_new(0); - gtk_paned_pack1(GTK_PANED(paned), sidebar, TRUE, FALSE); - - UiObject *left = uic_object_new(obj, sidebar); - UiContainer *ct1 = ui_box_container(obj, sidebar); - left->container = ct1; - - UiObject *right = uic_object_new(obj, sidebar); - UiContainer *ct2 = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct2->widget = paned; - ct2->add = ui_split_container_add2; - right->container = ct2; - - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, paned, TRUE); - - uic_obj_add(obj, right); - uic_obj_add(obj, left); - - return sidebar; -} -void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill) { - // TODO: remove - gtk_paned_pack1(GTK_PANED(ct->widget), widget, TRUE, FALSE); - - ui_reset_layout(ct->layout); - ct->current = widget; -} - -void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill) { - gtk_paned_pack2(GTK_PANED(ct->widget), widget, TRUE, FALSE); - - ui_reset_layout(ct->layout); - ct->current = widget; -} - - -/* -------------------- Document Tabview -------------------- */ -static void page_change(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data) { - GQuark q = g_quark_from_static_string("ui.tab.object"); - UiObject *tab = g_object_get_qdata(G_OBJECT(page), q); - if(!tab) { - return; - } - - //printf("page_change: %d\n", page_num); - UiContext *ctx = tab->ctx; - uic_context_detach_all(ctx->parent); // TODO: fix? - ctx->parent->attach_document(ctx->parent, ctx->document); -} - -UiTabbedPane* ui_tabbed_document_view(UiObject *obj) { - GtkWidget *tabview = gtk_notebook_new(); - gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); - - g_signal_connect( - tabview, - "switch-page", - G_CALLBACK(page_change), - NULL); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, tabview, TRUE); - - UiTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(UiTabbedPane)); - tabbedpane->ctx = uic_current_obj(obj)->ctx; - tabbedpane->widget = tabview; - tabbedpane->document = NULL; - - return tabbedpane; -} - -UiObject* ui_document_tab(UiTabbedPane *view) { - GtkWidget *frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); - // TODO: label - gtk_notebook_append_page(GTK_NOTEBOOK(view->widget), frame, NULL); - - UiObject *tab = ui_malloc(view->ctx, sizeof(UiObject)); - tab->widget = NULL; // initialization for uic_context() - tab->ctx = uic_context(tab, view->ctx->allocator); - tab->ctx->parent = view->ctx; - tab->ctx->attach_document = uic_context_attach_document; - tab->ctx->detach_document2 = uic_context_detach_document2; - tab->widget = frame; - tab->window = view->ctx->obj->window; - tab->container = ui_frame_container(tab, frame); - tab->next = NULL; - - GQuark q = g_quark_from_static_string("ui.tab.object"); - g_object_set_qdata(G_OBJECT(frame), q, tab); - - return tab; -} - -void ui_tab_set_document(UiContext *ctx, void *document) { - // TODO: remove? - if(ctx->parent->document) { - //ctx->parent->detach_document(ctx->parent, ctx->parent->document); - } - //uic_context_set_document(ctx, document); - //uic_context_set_document(ctx->parent, document); - //ctx->parent->document = document; -} - -void ui_tab_detach_document(UiContext *ctx) { - // TODO: remove? - //uic_context_detach_document(ctx->parent); -} /* @@ -611,16 +367,21 @@ ct->layout.vexpand = expand; } -void ui_layout_width(UiObject *obj, int width) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.width = width; -} - void ui_layout_gridwidth(UiObject *obj, int width) { UiContainer *ct = uic_get_current_container(obj); ct->layout.gridwidth = width; } +void ui_layout_colspan(UiObject* obj, int cols) { + UiContainer* ct = uic_get_current_container(obj); + ct->layout.colspan = cols; +} + +void ui_layout_rowspan(UiObject* obj, int rows) { + UiContainer* ct = uic_get_current_container(obj); + ct->layout.rowspan = rows; +} + void ui_newline(UiObject *obj) { UiContainer *ct = uic_get_current_container(obj); ct->layout.newline = TRUE; diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/container.h --- a/ui/gtk/container.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/container.h Mon Feb 12 17:32:02 2024 +0100 @@ -62,6 +62,8 @@ UiBool vexpand; int width; int gridwidth; + int colspan; + int rowspan; }; struct UiContainer { @@ -108,6 +110,8 @@ UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame); void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); +UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type); + UiContainer* ui_box_container(UiObject *obj, GtkWidget *box); void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/dnd.c --- a/ui/gtk/dnd.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/dnd.c Mon Feb 12 17:32:02 2024 +0100 @@ -55,6 +55,7 @@ #define gtk_selection_data_get_uris selection_data_get_uris #endif +/* void ui_selection_settext(UiSelection *sel, char *str, int len) { // TODO: handle error? gtk_selection_data_set_text(sel->data, str, len); @@ -99,3 +100,4 @@ } return NULL; } +*/ diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/image.c --- a/ui/gtk/image.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/image.c Mon Feb 12 17:32:02 2024 +0100 @@ -75,9 +75,11 @@ return NULL; } +/* UiIcon* ui_icon(const char *name, int size) { return get_icon(name, size, ui_get_scalefactor()); } +*/ UiIcon* ui_icon_unscaled(const char *name, int size) { return get_icon(name, size, 1); @@ -99,6 +101,7 @@ return NULL; } +/* UiImage* ui_image(const char *filename) { return ui_named_image(filename, NULL); } @@ -129,6 +132,7 @@ } return img; } +*/ void ui_free_image(UiImage *img) { g_object_unref(img->pixbuf); diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/menu.c --- a/ui/gtk/menu.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/menu.c Mon Feb 12 17:32:02 2024 +0100 @@ -45,13 +45,12 @@ static ui_menu_add_f createMenuItem[] = { /* UI_MENU */ add_menu_widget, - /* UI_MENU_SUBMENU */ add_menu_widget, /* UI_MENU_ITEM */ add_menuitem_widget, - /* UI_MENU_STOCK_ITEM */ add_menuitem_st_widget, /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, - /* UI_MENU_CHECK_ITEM_NV */ add_checkitemnv_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, - /* UI_MENU_ITEM_LIST_NV */ NULL, // TODO + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, /* UI_MENU_SEPARATOR */ add_menuseparator_widget }; @@ -126,6 +125,7 @@ } } +/* void add_menuitem_st_widget( GtkWidget *parent, int index, @@ -161,6 +161,7 @@ uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); } } +*/ void add_menuseparator_widget( GtkWidget *parent, @@ -174,7 +175,7 @@ } void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { - UiCheckItem *ci = (UiCheckItem*)item; + UiMenuCheckItem *ci = (UiMenuCheckItem*)item; GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); @@ -198,6 +199,11 @@ } } +void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { + // TODO +} + +/* void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { UiCheckItemNV *ci = (UiCheckItemNV*)item; GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); @@ -214,6 +220,7 @@ // TODO: error } } +*/ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; @@ -227,7 +234,10 @@ ls->menu = GTK_MENU_SHELL(p); ls->index = index; ls->oldcount = 0; - ls->list = il->list; + + // TODO: + //ls->list = il->list; + ls->callback = il->callback; ls->userdata = il->userdata; diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/menu.h --- a/ui/gtk/menu.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/menu.h Mon Feb 12 17:32:02 2024 +0100 @@ -60,6 +60,7 @@ void add_menuitem_st_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); void add_menuseparator_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); void add_checkitem_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); +void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj); void add_checkitemnv_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_list_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/model.c --- a/ui/gtk/model.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/model.c Mon Feb 12 17:32:02 2024 +0100 @@ -436,6 +436,7 @@ { //printf("drag received\n"); UiListModel *model = UI_LIST_MODEL(drag_dest); + /* if(model->model->drop) { gint *indices = gtk_tree_path_get_indices(dest_path); gint row = indices[0]; @@ -449,6 +450,7 @@ s.data = selection_data; model->model->drop(&e, &s, model->var->value, row); } + */ return TRUE; } @@ -459,6 +461,7 @@ { //printf("row_drop_possible\n"); UiListModel *model = UI_LIST_MODEL(drag_dest); + /* if(model->model->candrop) { gint *indices = gtk_tree_path_get_indices(dest_path); gint row = indices[0]; @@ -472,6 +475,7 @@ s.data = selection_data; return model->model->candrop(&e, &s, model->var->value, row); } + */ return TRUE; } @@ -481,6 +485,7 @@ { //printf("row_draggable\n"); UiListModel *model = UI_LIST_MODEL(drag_source); + /* if(model->model->candrag) { gint *indices = gtk_tree_path_get_indices(path); gint row = indices[0]; @@ -492,6 +497,7 @@ e.intval = 0; return model->model->candrag(&e, model->var->value, row); } + */ return TRUE; } @@ -502,6 +508,7 @@ { //printf("drag_data_get\n"); UiListModel *model = UI_LIST_MODEL(drag_source); + /* if(model->model->data_get) { gint *indices = gtk_tree_path_get_indices(path); gint row = indices[0]; @@ -515,6 +522,7 @@ s.data = selection_data; model->model->data_get(&e, &s, model->var->value, row); } + */ return TRUE; } @@ -524,6 +532,7 @@ { //printf("drag_data_delete\n"); UiListModel *model = UI_LIST_MODEL(drag_source); + /* if(model->model->data_get) { gint *indices = gtk_tree_path_get_indices(path); gint row = indices[0]; @@ -535,5 +544,6 @@ e.intval = 0; model->model->data_delete(&e, model->var->value, row); } + */ return TRUE; } diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/text.c --- a/ui/gtk/text.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/text.c Mon Feb 12 17:32:02 2024 +0100 @@ -193,7 +193,7 @@ return str; } -void ui_textarea_set(UiText *text, char *str) { +void ui_textarea_set(UiText *text, const char *str) { gtk_text_buffer_set_text((GtkTextBuffer*)text->obj, str, -1); if(text->value.ptr) { text->value.free(text->value.ptr); @@ -632,7 +632,7 @@ } } -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { +UIWIDGET ui_textfield_deprecated(UiObject *obj, UiString *value) { return create_textfield(obj, 0, FALSE, FALSE, value); } @@ -648,7 +648,7 @@ return create_textfield_nv(obj, width, FALSE, FALSE, varname); } -UIWIDGET ui_frameless_textfield(UiObject *obj, UiString *value) { +UIWIDGET ui_frameless_textfield_deprecated(UiObject *obj, UiString *value) { return create_textfield(obj, 0, TRUE, FALSE, value); } @@ -656,7 +656,7 @@ return create_textfield_nv(obj, 0, TRUE, FALSE, varname); } -UIWIDGET ui_passwordfield(UiObject *obj, UiString *value) { +UIWIDGET ui_passwordfield_deprecated(UiObject *obj, UiString *value) { return create_textfield(obj, 0, FALSE, TRUE, value); } @@ -681,7 +681,7 @@ return str->value.ptr; } -void ui_textfield_set(UiString *str, char *value) { +void ui_textfield_set(UiString *str, const char *value) { gtk_entry_set_text(str->obj, value); if(str->value.ptr) { str->value.free(str->value.ptr); diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/text.h --- a/ui/gtk/text.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/text.h Mon Feb 12 17:32:02 2024 +0100 @@ -76,7 +76,7 @@ void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea); char* ui_textarea_get(UiText *text); -void ui_textarea_set(UiText *text, char *str); +void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); void ui_textarea_insert(UiText *text, int pos, char *str); void ui_textarea_setposition(UiText *text, int pos); @@ -108,7 +108,7 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield); char* ui_textfield_get(UiString *str); -void ui_textfield_set(UiString *str, char *value); +void ui_textfield_set(UiString *str, const char *value); #ifdef __cplusplus } diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/toolbar.c --- a/ui/gtk/toolbar.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/toolbar.c Mon Feb 12 17:32:02 2024 +0100 @@ -34,7 +34,7 @@ #include "button.h" #include "image.h" #include "tree.h" -#include +#include #include #include #include @@ -221,11 +221,6 @@ } -void ui_toolbar_add_default(char *name) { - char *s = strdup(name); - cxListAdd(defaults, s); -} - GtkWidget* ui_create_toolbar(UiObject *obj) { if(!defaults) { return NULL; diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/toolkit.c --- a/ui/gtk/toolkit.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/toolkit.c Mon Feb 12 17:32:02 2024 +0100 @@ -48,7 +48,7 @@ static GtkApplication *app; #endif -static char *application_name; +static const char *application_name; static ui_callback startup_func; static void *startup_data; @@ -64,14 +64,16 @@ static int scale_factor = 1; -void ui_init(char *appname, int argc, char **argv) { +UIEXPORT void ui_init(const char *appname, int argc, char **argv) { uic_init_global_context(); gtk_init(&argc, &argv); application_name = appname; uic_docmgr_init(); - ui_toolbar_init(); + ui_toolbar_init(); // TODO: remove + + uic_toolbar_init(); // init custom types ui_list_init(); @@ -86,7 +88,7 @@ #endif } -char* ui_appname() { +const char* ui_appname() { return application_name; } diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/tree.c --- a/ui/gtk/tree.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/tree.c Mon Feb 12 17:32:02 2024 +0100 @@ -43,9 +43,7 @@ } -UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_listview(obj, list, ui_strmodel_getvalue, f, udata); -} + UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { // create treeview @@ -119,7 +117,7 @@ return scroll_area; } -UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { +UIWIDGET ui_listview_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { UiVar *var = malloc(sizeof(UiVar)); var->value = list; var->type = UI_VAR_SPECIAL; @@ -270,7 +268,7 @@ return scroll_area; } -UIWIDGET ui_table(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) { +UIWIDGET ui_table_deprecated(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) { UiVar *var = malloc(sizeof(UiVar)); var->value = list; var->type = UI_VAR_SPECIAL; @@ -329,10 +327,14 @@ int nelm; char **targets = targets2array(target0, ap, &nelm); va_end(ap); - ui_table_dragsource_a(tablewidget, actions, targets, nelm); + + // disabled + //ui_table_dragsource_a(tablewidget, actions, targets, nelm); + free(targets); } +/* void ui_table_dragsource_a(UIWIDGET tablewidget, int actions, char **targets, int nelm) { GtkTargetEntry* t = targetstr2gtktargets(targets, nelm); gtk_tree_view_enable_model_drag_source( @@ -344,6 +346,7 @@ free(t); } + void ui_table_dragdest(UIWIDGET tablewidget, int actions, char *target0, ...) { va_list ap; va_start(ap, target0); @@ -363,7 +366,8 @@ GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK); free(t); } - +*/ + void ui_listview_update(UiList *list, int i) { UiListView *view = list->obj; UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); @@ -464,11 +468,7 @@ /* --------------------------- ComboBox --------------------------- */ -UIWIDGET ui_combobox_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_combobox(obj, list, ui_strmodel_getvalue, f, udata); -} - -UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { +UIWIDGET ui_combobox_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { UiVar *var = malloc(sizeof(UiVar)); var->value = list; var->type = UI_VAR_SPECIAL; diff -r 1ecc1183f046 -r 3fc287f06305 ui/gtk/window.c --- a/ui/gtk/window.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/gtk/window.c Mon Feb 12 17:32:02 2024 +0100 @@ -33,8 +33,10 @@ #include "../ui/window.h" #include "../ui/properties.h" #include "../common/context.h" +#include "../common/menu.h" +#include "../common/toolbar.h" -#include +#include #include "menu.h" #include "toolbar.h" @@ -67,7 +69,7 @@ #endif } -static UiObject* create_window(char *title, void *window_data, UiBool simple) { +static UiObject* create_window(const char *title, void *window_data, UiBool simple) { CxMempool *mp = cxBasicMempoolCreate(256); UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); @@ -78,7 +80,7 @@ #endif - obj->ctx = uic_context(obj, mp->allocator); + obj->ctx = uic_context(obj, mp); obj->window = window_data; if(title != NULL) { @@ -110,15 +112,19 @@ if(!simple) { // menu - GtkWidget *mb = ui_create_menubar(obj); - if(mb) { - gtk_box_pack_start(GTK_BOX(vbox), mb, FALSE, FALSE, 0); + if(uic_get_menu_list()) { + GtkWidget *mb = ui_create_menubar(obj); + if(mb) { + gtk_box_pack_start(GTK_BOX(vbox), mb, FALSE, FALSE, 0); + } } // toolbar - GtkWidget *tb = ui_create_toolbar(obj); - if(tb) { - gtk_box_pack_start(GTK_BOX(vbox), tb, FALSE, FALSE, 0); + if(uic_toolbar_isenabled()) { + GtkWidget *tb = ui_create_toolbar(obj); + if(tb) { + gtk_box_pack_start(GTK_BOX(vbox), tb, FALSE, FALSE, 0); + } } } @@ -138,11 +144,11 @@ } -UiObject* ui_window(char *title, void *window_data) { +UiObject* ui_window(const char *title, void *window_data) { return create_window(title, window_data, FALSE); } -UiObject* ui_simplewindow(char *title, void *window_data) { +UiObject* ui_simplewindow(const char *title, void *window_data) { return create_window(title, window_data, TRUE); } @@ -179,11 +185,4 @@ } } -char* ui_openfiledialog(UiObject *obj) { - return ui_gtkfilechooser(obj, GTK_FILE_CHOOSER_ACTION_OPEN); -} -char* ui_savefiledialog(UiObject *obj) { - return ui_gtkfilechooser(obj, GTK_FILE_CHOOSER_ACTION_SAVE); -} - diff -r 1ecc1183f046 -r 3fc287f06305 ui/motif/container.c --- a/ui/motif/container.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/motif/container.c Mon Feb 12 17:32:02 2024 +0100 @@ -674,7 +674,7 @@ UiObject *content = ui_malloc(view->ctx, sizeof(UiObject)); content->widget = NULL; // initialization for uic_context() - content->ctx = uic_context(content, view->ctx->allocator); + content->ctx = uic_context(content, view->ctx->mp); content->ctx->parent = view->ctx; content->ctx->attach_document = uic_context_attach_document; content->ctx->detach_document2 = uic_context_detach_document2; diff -r 1ecc1183f046 -r 3fc287f06305 ui/motif/text.c --- a/ui/motif/text.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/motif/text.c Mon Feb 12 17:32:02 2024 +0100 @@ -119,7 +119,7 @@ return str; } -void ui_textarea_set(UiText *text, char *str) { +void ui_textarea_set(UiText *text, const char *str) { XmTextSetString(text->obj, str); if(text->value.ptr) { text->value.free(text->value.ptr); diff -r 1ecc1183f046 -r 3fc287f06305 ui/motif/text.h --- a/ui/motif/text.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/motif/text.h Mon Feb 12 17:32:02 2024 +0100 @@ -64,7 +64,7 @@ } UiTextArea; char* ui_textarea_get(UiText *text); -void ui_textarea_set(UiText *text, char *str); +void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); void ui_textarea_insert(UiText *text, int pos, char *str); void ui_textarea_setposition(UiText *text, int pos); diff -r 1ecc1183f046 -r 3fc287f06305 ui/motif/window.c --- a/ui/motif/window.c Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/motif/window.c Mon Feb 12 17:32:02 2024 +0100 @@ -36,7 +36,7 @@ #include "../ui/window.h" #include "../common/context.h" -#include +#include static int nwindows = 0; @@ -67,7 +67,7 @@ CxMempool *mp = cxBasicMempoolCreate(256); const CxAllocator *a = mp->allocator; UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); - obj->ctx = uic_context(obj, a); + obj->ctx = uic_context(obj, mp); obj->window = window_data; Arg args[16]; diff -r 1ecc1183f046 -r 3fc287f06305 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/ui/toolkit.h Mon Feb 12 17:32:02 2024 +0100 @@ -297,7 +297,7 @@ }; struct UiText { - void (*set)(UiText*, char*); + void (*set)(UiText*, const char*); char* (*get)(UiText*); char* (*getsubstr)(UiText*, int, int); /* text, begin, end */ void (*insert)(UiText*, int, char*); diff -r 1ecc1183f046 -r 3fc287f06305 ui/ui/window.h --- a/ui/ui/window.h Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/ui/window.h Mon Feb 12 17:32:02 2024 +0100 @@ -60,7 +60,7 @@ UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs args); UIEXPORT void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata); -UIEXPORT void ui_savefiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata); +UIEXPORT void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata); diff -r 1ecc1183f046 -r 3fc287f06305 ui/winui/window.cpp --- a/ui/winui/window.cpp Sun Feb 11 15:59:56 2024 +0100 +++ b/ui/winui/window.cpp Mon Feb 12 17:32:02 2024 +0100 @@ -46,6 +46,10 @@ #include "MainWindow.xaml.h" +#include +#include +#include + using namespace winrt; using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; @@ -357,6 +361,59 @@ } } +static Windows::Foundation::IAsyncAction save_filedialog_async(UiObject *obj, char *name, ui_callback file_selected_callback, void *cbdata) { + IFileSaveDialog *saveFileDialog; + + HRESULT hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL, IID_IFileSaveDialog, reinterpret_cast(&saveFileDialog)); + if (FAILED(hr)) + { + co_return; + } + + if (name) { + wchar_t *wname = str2wstr(name, NULL); + saveFileDialog->SetFileName(wname); + free(wname); + free(name); + } + + + hr = saveFileDialog->Show(NULL); + if (SUCCEEDED(hr)) { + IShellItem *item; + hr = saveFileDialog->GetResult(&item); + if (SUCCEEDED(hr)) { + PWSTR wpath; + hr = item->GetDisplayName(SIGDN_FILESYSPATH, &wpath); + + if (SUCCEEDED(hr)) { + char *path = wchar2utf8(wpath, lstrlen(wpath)); + CoTaskMemFree(wpath); + + UiFileList flist; + flist.nfiles = 1; + flist.files = new char*[1]; + flist.files[0] = path; + + UiEvent evt; + evt.obj = obj; + evt.document = obj->ctx->document; + evt.window = obj->window; + evt.eventdata = &flist; + evt.intval = 0; + file_selected_callback(&evt, cbdata); + + free(path); + delete[] flist.files; + } + item->Release(); + } + } + + // cleanup + saveFileDialog->Release(); +} + static Windows::Foundation::IAsyncAction folderdialog_async(UiObject *obj, ui_callback file_selected_callback, void *cbdata) { FolderPicker folderPicker = FolderPicker(); auto initializeWithWindow { folderPicker.as<::IInitializeWithWindow>() @@ -396,6 +453,7 @@ } } -UIEXPORT void ui_savefiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) { - +UIEXPORT void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) { + char *n = name ? _strdup(name) : NULL; + save_filedialog_async(obj, n, file_selected_callback, cbdata); }