Sun, 29 Sep 2024 15:55:56 +0200
implement file dialog for gtk4
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "toolbar.h" #include "menu.h" #include "button.h" #include "image.h" #include "tree.h" #include <cx/mempool.h> #include <cx/hash_map.h> #include <cx/linked_list.h> #include <cx/array_list.h> #include "../common/context.h" #if UI_GTK2 || UI_GTK3 GtkWidget* ui_create_toolbar(UiObject *obj) { GtkWidget *toolbar = gtk_toolbar_new(); #ifdef UI_GTK3 gtk_style_context_add_class( gtk_widget_get_style_context(toolbar), GTK_STYLE_CLASS_PRIMARY_TOOLBAR); #endif CxMap *items = uic_get_toolbar_items(); CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); ui_toolbar_add_items(obj, toolbar, items, left_defaults); ui_toolbar_add_items(obj, toolbar, items, center_defaults); ui_toolbar_add_items(obj, toolbar, items, right_defaults); /* GtkToolbar *tb = GTK_TOOLBAR(toolbar); CxIterator i = cxListIterator(defaults); cx_foreach(char *, def, i) { UiToolItemI *item = cxMapGet(toolbar_items, def); if(item) { item->add_to(tb, item, obj); } else if(!strcmp(def, "@separator")) { gtk_toolbar_insert(tb, gtk_separator_tool_item_new(), -1); } else { fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); } } */ return toolbar; } static void create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { GtkToolbar *tb = GTK_TOOLBAR(toolbar); switch(i->type) { case UI_TOOLBAR_ITEM: { add_toolitem_widget(tb, (UiToolbarItem*)i, obj); break; } case UI_TOOLBAR_TOGGLEITEM: { add_toolitem_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); break; } case UI_TOOLBAR_MENU: { add_toolitem_menu_widget(tb, (UiToolbarMenuItem*)i, obj); break; } default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); } } void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults) { // add pre-configured items CxIterator i = cxListIterator(defaults); cx_foreach(char*, def, i) { UiToolbarItemI* item = uic_toolbar_get_item(def); if (!item) { fprintf(stderr, "unknown toolbar item: %s\n", def); continue; } create_item(obj, toolbar, item); } } static void set_toolbutton_icon(GtkToolItem *item, const char *icon_name) { #if GTK_MAJOR_VERSION >= 3 gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), icon_name); #else UiIcon *icon = ui_icon(icon_name, 24); if(icon) { GdkPixbuf *pixbuf = ui_icon_pixbuf(icon); if(pixbuf) { GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), image); } } #endif } void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) { GtkToolItem *button; if(item->args.stockid) { #ifdef UI_GTK2 button = gtk_tool_button_new_from_stock(item->args.stockid); #else // TODO: gtk3 stock button = gtk_tool_button_new(NULL, item->args.label); #endif } else { button = gtk_tool_button_new(NULL, item->args.label); } gtk_tool_item_set_homogeneous(button, FALSE); if(item->args.icon) { set_toolbutton_icon(button, item->args.icon); } gtk_tool_item_set_is_important(button, TRUE); if(item->args.onclick) { UiEventData *event = cxMalloc( obj->ctx->allocator, sizeof(UiEventData)); event->obj = obj; event->callback = item->args.onclick; event->userdata = item->args.onclickdata; event->customdata = NULL; event->value = 0; g_signal_connect( button, "clicked", G_CALLBACK(ui_button_clicked), event); } gtk_toolbar_insert(tb, button, -1); /* if(item->groups) { uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); } */ } void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj) { GtkToolItem *button; if(item->args.stockid) { #ifdef UI_GTK2 button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); #else button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); // TODO: gtk3 stock #endif } else { button = gtk_toggle_tool_button_new(); gtk_tool_item_set_homogeneous(button, FALSE); if(item->args.label) { gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label); } if(item->args.icon) { set_toolbutton_icon(button, item->args.icon); } } UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER); if(var) { UiInteger *i = (UiInteger*)var->value; if(i) { i->get = ui_tool_toggle_button_get; i->set = ui_tool_toggle_button_set; i->obj = button; if(i->value != 0) { gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), TRUE); } } } UiVarEventData *event = cxMalloc( obj->ctx->allocator, sizeof(UiVarEventData)); event->obj = obj; event->callback = item->args.onchange; event->userdata = item->args.onchangedata; event->var = var; g_signal_connect( button, "toggled", G_CALLBACK(ui_tool_button_toggled), event); // add item to toolbar gtk_toolbar_insert(tb, button, -1); /* if(item->groups) { uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); } */ } void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event) { UiEvent e; e.obj = event->obj; e.window = event->obj->window; e.document = event->obj->ctx->document; e.eventdata = NULL; e.intval = gtk_toggle_tool_button_get_active(widget); if(event->callback) { event->callback(&e, event->userdata); } UiVar *var = event->var; UiInteger *i = var ? var->value : NULL; if(i) { ui_notify_evt(i->observers, &e); } } int64_t ui_tool_toggle_button_get(UiInteger *integer) { integer->value = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj)); return integer->value; } void ui_tool_toggle_button_set(UiInteger *integer, int64_t value) { gboolean s = value != 0 ? TRUE : FALSE; gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj), s); integer->value = s; } typedef struct UiToolbarMenuWidget { GtkWidget *button; GtkMenu *menu; } UiToolbarMenuWidget; static void ui_toolbar_menubutton_clicked(GtkWidget *widget, UiToolbarMenuWidget *menu) { int x; gtk_menu_popup_at_widget(menu->menu, menu->button, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL); } static void ui_toolbar_menubutton_destroy(GtkWidget *widget, UiToolbarMenuWidget *menu) { free(menu); } void add_toolitem_menu_widget(GtkToolbar *tb, UiToolbarMenuItem *item, UiObject *obj) { GtkToolItem *button; if(item->args.stockid) { #ifdef UI_GTK2 button = gtk_tool_button_new_from_stock(item->args.stockid); #else // TODO: gtk3 stock button = gtk_tool_button_new(NULL, item->args.label); #endif } else { button = gtk_tool_button_new(NULL, item->args.label); } gtk_tool_item_set_homogeneous(button, FALSE); if(item->args.icon) { set_toolbutton_icon(button, item->args.icon); } gtk_tool_item_set_is_important(button, TRUE); gtk_toolbar_insert(tb, button, -1); // menu GtkWidget *menu_widget = gtk_menu_new(); ui_add_menu_items(menu_widget, 0, &item->menu, obj); gtk_widget_show_all(menu_widget); UiToolbarMenuWidget *tbmenu = malloc(sizeof(UiToolbarMenuWidget)); tbmenu->button = GTK_WIDGET(button); tbmenu->menu = GTK_MENU(menu_widget); g_signal_connect( button, "clicked", G_CALLBACK(ui_toolbar_menubutton_clicked), tbmenu); g_signal_connect( button, "destroy", G_CALLBACK(ui_toolbar_menubutton_destroy), tbmenu); } // deprecated / unsupported /* void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) { UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); modelinfo->getvalue = cb->getvalue; UiListModel *model = ui_list_model_new(obj, cb->var, modelinfo); GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata); GtkToolItem *item = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(item), combobox); gtk_toolbar_insert(tb, item, -1); } void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj) { UiVar *var = uic_create_var(obj->ctx, cb->listname, UI_VAR_LIST); if(var) { UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); modelinfo->getvalue = cb->getvalue; UiListModel *model = ui_list_model_new(obj, var, modelinfo); GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata); GtkToolItem *item = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(item), combobox); gtk_toolbar_insert(tb, item, -1); } } */ #ifdef UI_GTK3 GtkWidget* ui_create_headerbar(UiObject *obj) { GtkWidget *headerbar = gtk_header_bar_new(); CxMap *items = uic_get_toolbar_items(); CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); ui_toolbar_headerbar_add_items(obj, headerbar, items, left_defaults); ui_toolbar_headerbar_add_items(obj, headerbar, items, center_defaults); ui_toolbar_headerbar_add_items(obj, headerbar, items, right_defaults); return headerbar; } static void hb_create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { GtkHeaderBar *tb = GTK_HEADER_BAR(toolbar); switch(i->type) { case UI_TOOLBAR_ITEM: { add_headerbar_item_widget(tb, (UiToolbarItem*)i, obj); break; } case UI_TOOLBAR_TOGGLEITEM: { add_headerbar_item_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); break; } case UI_TOOLBAR_MENU: { add_headerbar_item_menu_widget(tb, (UiToolbarMenuItem*)i, obj); break; } default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); } } void ui_toolbar_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxMap *items, CxList *defaults) { // add pre-configured items CxIterator i = cxListIterator(defaults); cx_foreach(char*, def, i) { UiToolbarItemI* item = uic_toolbar_get_item(def); if (!item) { fprintf(stderr, "unknown toolbar item: %s\n", def); continue; } hb_create_item(obj, headerbar, item); } } void add_headerbar_item_widget(GtkHeaderBar *hb, UiToolbarItem *item, UiObject *obj) { GtkWidget *button = gtk_button_new_with_label(item->args.label); if(item->args.icon) { ui_button_set_icon_name(button, item->args.icon); } gtk_header_bar_pack_start(hb, button); } void add_headerbar_item_toggle_widget(GtkHeaderBar *hb, UiToolbarToggleItem *item, UiObject *obj) { } void add_headerbar_item_menu_widget(GtkHeaderBar *hb, UiToolbarMenuItem *item, UiObject *obj) { } #endif /* UI_GTK3 */ #endif /* UI_GTK2 || UI_GTK3 */