diff -r 9e2aee097b69 -r 132c7bcc6997 ui/gtk/toolbar.c --- a/ui/gtk/toolbar.c Sun Mar 31 09:58:07 2024 +0200 +++ b/ui/gtk/toolbar.c Sun Mar 31 16:19:01 2024 +0200 @@ -31,6 +31,7 @@ #include #include "toolbar.h" +#include "menu.h" #include "button.h" #include "image.h" #include "tree.h" @@ -40,192 +41,8 @@ #include #include "../common/context.h" -static CxMap *toolbar_items; -static CxList *defaults; - -void ui_toolbar_init() { - toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - defaults = cxLinkedListCreateSimple(CX_STORE_POINTERS); -} - -void ui_toolitem(char *name, char *label, ui_callback f, void *udata) { - ui_toolitem_img(name, label, NULL, f, udata); -} - -void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgr(name, stockid, f, userdata, -1); -} - -void ui_toolitem_sti(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgri(name, stockid, f, userdata, -1); -} - -void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 0, f, userdata, ap); - va_end(ap); -} - -void ui_toolitem_stgri(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 1, f, userdata, ap); - va_end(ap); -} - -void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) { - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->isimportant = 0; - item->groups = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_vstgr( - char *name, - char *stockid, - int isimportant, - ui_callback f, - void *userdata, - va_list ap) -{ - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = isimportant; - - // add groups - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle(const char *name, const char *label, const char *img, UiInteger *i) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->stockid = NULL; - item->groups = NULL; - item->isimportant = 0; - item->value = i; - item->var = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_st(const char *name, const char *stockid, UiInteger *i) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = NULL; - item->image = NULL; - item->stockid = stockid; - item->groups = NULL; - item->isimportant = 0; - item->value = i; - item->var = NULL; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_nv(const char *name, const char *label, const char *img, const char *intvar) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->stockid = NULL; - item->groups = NULL; - item->isimportant = 0; - item->value = NULL; - item->var = intvar; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_stnv(const char *name, const char *stockid, const char *intvar) { - UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = NULL; - item->image = NULL; - item->stockid = stockid; - item->groups = NULL; - item->isimportant = 0; - item->value = NULL; - item->var = intvar; - - cxMapPut(toolbar_items, name, item); -} - - -void ui_toolbar_combobox( - char *name, - UiList *list, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox; - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - cb->var = var; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - -void ui_toolbar_combobox_str( - char *name, - UiList *list, - ui_callback f, - void *udata) -{ - ui_toolbar_combobox(name, list, ui_strmodel_getvalue, f, udata); -} - -void ui_toolbar_combobox_nv( - char *name, - char *listname, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBoxNV *cb = malloc(sizeof(UiToolbarComboBoxNV)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox_nv; - cb->listname = listname; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - GtkWidget* ui_create_toolbar(UiObject *obj) { - if(!defaults) { - return NULL; - } - GtkWidget *toolbar = gtk_toolbar_new(); #ifdef UI_GTK3 gtk_style_context_add_class( @@ -233,6 +50,16 @@ 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) { @@ -245,57 +72,84 @@ fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); } } + */ return toolbar; } -void add_toolitem_widget(GtkToolbar *tb, UiToolItem *item, UiObject *obj) { - GtkToolItem *button = gtk_tool_button_new(NULL, item->label); - gtk_tool_item_set_homogeneous(button, FALSE); - if(item->image) { - GdkPixbuf *pixbuf = ui_get_image(item->image); - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image); +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 { - gtk_tool_item_set_is_important(button, TRUE); + button = gtk_tool_button_new(NULL, item->args.label); } - if(item->callback) { + 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->userdata = item->userdata; - event->callback = item->callback; - - 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_st_widget(GtkToolbar *tb, UiStToolItem *item, UiObject *obj) { - GtkToolItem *button = gtk_tool_button_new_from_stock(item->stockid); - gtk_tool_item_set_homogeneous(button, FALSE); - if(item->isimportant) { - gtk_tool_item_set_is_important(button, TRUE); - } - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; + event->callback = item->args.onclick; + event->userdata = item->args.onclickdata; g_signal_connect( button, @@ -306,74 +160,71 @@ 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, UiToggleToolItem *item, UiObject *obj) { +void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj) { GtkToolItem *button; - if(item->stockid) { - button = gtk_toggle_tool_button_new_from_stock(item->stockid); + 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->label) { - gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->label); + if(item->args.label) { + gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label); } - if(item->image) { - GdkPixbuf *pixbuf = ui_get_image(item->image); - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image); + if(item->args.icon) { + set_toolbutton_icon(button, item->args.icon); } } - UiVar *var; - if(item->value) { - var = malloc(sizeof(UiVar)); - var->value = item->value; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - } else { - var = uic_create_var(obj->ctx, item->var, UI_VAR_INTEGER); - } - - if(var->value) { - UiInteger *i = var->value; - 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); + 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); + } } } - // register event - // the event func will call the UiInteger observer callbacks - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); + UiVarEventData *event = cxMalloc( + obj->ctx->allocator, + sizeof(UiVarEventData)); event->obj = obj; - event->userdata = var; - event->callback = NULL; + 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); + 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, UiEventData *event) { +void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event) { UiEvent e; e.obj = event->obj; e.window = event->obj->window; @@ -381,10 +232,16 @@ e.eventdata = NULL; e.intval = gtk_toggle_tool_button_get_active(widget); - UiVar *var = event->userdata; - UiInteger *i = var->value; + if(event->callback) { + event->callback(&e, event->userdata); + } - ui_notify_evt(i->observers, &e); + 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) { @@ -398,6 +255,70 @@ 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; @@ -422,4 +343,5 @@ gtk_toolbar_insert(tb, item, -1); } } +*/