2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2017 Olaf Wintermann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
36 #include "../common/context.h"
37 #include "../ui/properties.h"
38 #include "../ui/window.h"
39 #include "container.h"
41 static UcxList *menus;
42 static UcxList *current;
44 void ui_menu(char *label) {
45 // free current menu hierarchy
46 ucx_list_free(current);
49 UiMenu *menu = malloc(sizeof(UiMenu));
50 menu->item.add_to = (ui_menu_add_f)add_menu_widget;
56 current = ucx_list_prepend(NULL, menu);
57 menus = ucx_list_append(menus, menu);
61 void ui_submenu(char *label) {
62 UiMenu *menu = malloc(sizeof(UiMenu));
63 menu->item.add_to = (ui_menu_add_f)add_menu_widget;
69 // add submenu to current menu
70 UiMenu *cm = current->data;
71 cm->items = ucx_list_append(cm->items, menu);
73 // set the submenu to current menu
74 current = ucx_list_prepend(current, menu);
77 void ui_submenu_end() {
78 if(ucx_list_size(current) < 2) {
81 current = ucx_list_remove(current, current);
82 //UcxList *c = current;
85 void ui_menuitem(char *label, ui_callback f, void *userdata) {
86 ui_menuitem_gr(label, f, userdata, -1);
89 void ui_menuitem_st(char *stockid, ui_callback f, void *userdata) {
90 ui_menuitem_stgr(stockid, f, userdata, -1);
93 void ui_menuitem_gr(char *label, ui_callback f, void *userdata, ...) {
98 UiMenuItem *item = malloc(sizeof(UiMenuItem));
99 item->item.add_to = (ui_menu_add_f)add_menuitem_widget;
102 item->userdata = userdata;
108 va_start(ap, userdata);
110 while((group = va_arg(ap, int)) != -1) {
111 item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group);
115 UiMenu *cm = current->data;
116 cm->items = ucx_list_append(cm->items, item);
119 void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) {
124 UiStMenuItem *item = malloc(sizeof(UiStMenuItem));
125 item->item.add_to = (ui_menu_add_f)add_menuitem_st_widget;
127 item->stockid = stockid;
128 item->userdata = userdata;
134 va_start(ap, userdata);
136 while((group = va_arg(ap, int)) != -1) {
137 item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group);
141 UiMenu *cm = current->data;
142 cm->items = ucx_list_append(cm->items, item);
145 void ui_menuseparator() {
150 UiMenuItemI *item = malloc(sizeof(UiMenuItemI));
151 item->add_to = (ui_menu_add_f)add_menuseparator_widget;
153 UiMenu *cm = current->data;
154 cm->items = ucx_list_append(cm->items, item);
157 void ui_checkitem(char *label, ui_callback f, void *userdata) {
162 UiCheckItem *item = malloc(sizeof(UiCheckItem));
163 item->item.add_to = (ui_menu_add_f)add_checkitem_widget;
166 item->userdata = userdata;
168 UiMenu *cm = current->data;
169 cm->items = ucx_list_append(cm->items, item);
172 void ui_checkitem_nv(char *label, char *vname) {
177 UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV));
178 item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget;
179 item->varname = vname;
182 UiMenu *cm = current->data;
183 cm->items = ucx_list_append(cm->items, item);
186 void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) {
191 UiMenuItemList *item = malloc(sizeof(UiMenuItemList));
192 item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget;
194 item->userdata = userdata;
197 UiMenu *cm = current->data;
198 cm->items = ucx_list_append(cm->items, item);
201 // private menu functions
202 GtkWidget *ui_create_menubar(UiObject *obj) {
207 GtkWidget *mb = gtk_menu_bar_new();
211 UiMenu *menu = ls->data;
212 menu->item.add_to(mb, 0, &menu->item, obj);
220 void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) {
221 UiMenu *menu = (UiMenu*)item;
223 GtkWidget *menu_widget = gtk_menu_new();
224 GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label);
225 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget);
227 UcxList *ls = menu->items;
230 UiMenuItemI *i = ls->data;
231 i->add_to(menu_widget, index, i, obj);
237 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item);
240 void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObject *obj) {
241 UiMenuItem *i = (UiMenuItem*)item;
243 //GtkWidget *widget = gtk_menu_item_new_with_label(i->title);
244 GtkWidget *widget = gtk_menu_item_new_with_mnemonic(i->label);
246 if(i->callback != NULL) {
247 UiEventData *event = malloc(sizeof(UiEventData));
249 event->userdata = i->userdata;
250 event->callback = i->callback;
256 G_CALLBACK(ui_menu_event_wrapper),
261 G_CALLBACK(ui_destroy_userdata),
265 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
268 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
272 void add_menuitem_st_widget(
278 UiStMenuItem *i = (UiStMenuItem*)item;
280 GtkWidget *widget = gtk_image_menu_item_new_from_stock(i->stockid, obj->ctx->accel_group);
282 if(i->callback != NULL) {
283 UiEventData *event = malloc(sizeof(UiEventData));
285 event->userdata = i->userdata;
286 event->callback = i->callback;
292 G_CALLBACK(ui_menu_event_wrapper),
297 G_CALLBACK(ui_destroy_userdata),
301 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
304 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
308 void add_menuseparator_widget(
314 gtk_menu_shell_append(
315 GTK_MENU_SHELL(parent),
316 gtk_separator_menu_item_new());
319 void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
320 UiCheckItem *ci = (UiCheckItem*)item;
321 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
322 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
325 UiEventData *event = malloc(sizeof(UiEventData));
327 event->userdata = ci->userdata;
328 event->callback = ci->callback;
334 G_CALLBACK(ui_menu_event_toggled),
339 G_CALLBACK(ui_destroy_userdata),
344 void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
345 UiCheckItemNV *ci = (UiCheckItemNV*)item;
346 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
347 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
349 UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER);
351 UiInteger *value = var->value;
353 value->get = ui_checkitem_get;
354 value->set = ui_checkitem_set;
361 void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
362 UiMenuItemList *il = (UiMenuItemList*)item;
363 UcxMempool *mp = obj->ctx->mempool;
365 UiActiveMenuItemList *ls = ucx_mempool_malloc(
367 sizeof(UiActiveMenuItemList));
370 ls->menu = GTK_MENU_SHELL(p);
374 ls->callback = il->callback;
375 ls->userdata = il->userdata;
377 ls->list->observers = ui_add_observer(
379 (ui_callback)ui_update_menuitem_list,
382 ui_update_menuitem_list(NULL, ls);
386 void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
388 if(list->oldcount > 0) {
390 GList *mi = gtk_container_get_children(GTK_CONTAINER(list->menu));
392 if(i >= list->index && i < list->index + list->oldcount) {
393 //gtk_container_remove(GTK_CONTAINER(list->menu), mi->data);
394 gtk_widget_destroy(mi->data);
401 char *str = ui_list_first(list->list);
403 GtkWidget *widget = gtk_separator_menu_item_new();
404 gtk_menu_shell_insert(list->menu, widget, list->index);
405 gtk_widget_show(widget);
409 GtkWidget *widget = gtk_menu_item_new_with_label(str);
410 gtk_menu_shell_insert(list->menu, widget, list->index + i);
411 gtk_widget_show(widget);
415 UiEventData *event = malloc(sizeof(UiEventData));
416 event->obj = list->object;
417 event->userdata = list->userdata;
418 event->callback = list->callback;
419 event->value = i - 1;
424 G_CALLBACK(ui_menu_event_wrapper),
429 G_CALLBACK(ui_destroy_userdata),
433 str = ui_list_next(list->list);
440 void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) {
442 evt.obj = event->obj;
443 evt.window = event->obj->window;
444 evt.document = event->obj->ctx->document;
445 evt.eventdata = NULL;
446 evt.intval = event->value;
447 event->callback(&evt, event->userdata);
450 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
452 evt.obj = event->obj;
453 evt.window = event->obj->window;
454 evt.document = event->obj->ctx->document;
455 evt.eventdata = NULL;
456 evt.intval = gtk_check_menu_item_get_active(ci);
457 event->callback(&evt, event->userdata);
460 int64_t ui_checkitem_get(UiInteger *i) {
461 int state = gtk_check_menu_item_get_active(i->obj);
466 void ui_checkitem_set(UiInteger *i, int64_t value) {
468 gtk_check_menu_item_set_active(i->obj, value);
473 * widget menu functions
476 static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) {
477 if(event->type == GDK_BUTTON_PRESS) {
478 GdkEventButton *e = (GdkEventButton*)event;
480 gtk_widget_show_all(GTK_WIDGET(menu));
481 ui_contextmenu_popup(menu);
488 UIMENU ui_contextmenu(UiObject *obj) {
489 UiContainer *ct = uic_get_current_container(obj);
490 return ui_contextmenu_w(obj, ct->current);
493 UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) {
494 UiContainer *ct = uic_get_current_container(obj);
496 GtkMenu *menu = GTK_MENU(gtk_menu_new());
497 g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu);
503 void ui_contextmenu_popup(UIMENU menu) {
504 #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16
505 gtk_menu_popup_at_pointer(menu, NULL);
507 gtk_menu_popup(menu, NULL, NULL, 0, 0, 0, gtk_get_current_event_time());
511 void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) {
512 ui_widget_menuitem_gr(obj, label, f, userdata, -1);
515 void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) {
516 UiContainer *ct = uic_get_current_container(obj);
522 UcxList *groups = NULL;
524 va_start(ap, userdata);
526 while((group = va_arg(ap, int)) != -1) {
527 ucx_list_append(groups, (void*)(intptr_t)group);
532 GtkWidget *widget = gtk_menu_item_new_with_mnemonic(label);
533 gtk_widget_show(widget);
536 UiEventData *event = malloc(sizeof(UiEventData));
538 event->userdata = userdata;
545 G_CALLBACK(ui_menu_event_wrapper),
550 G_CALLBACK(ui_destroy_userdata),
554 gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget);
557 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
561 void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) {
562 ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1);
565 void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) {
566 UiContainer *ct = uic_get_current_container(obj);
572 UcxList *groups = NULL;
574 va_start(ap, userdata);
576 while((group = va_arg(ap, int)) != -1) {
577 ucx_list_append(groups, (void*)(intptr_t)group);
582 GtkWidget *widget = gtk_image_menu_item_new_from_stock(stockid, obj->ctx->accel_group);
583 gtk_widget_show(widget);
586 UiEventData *event = malloc(sizeof(UiEventData));
588 event->userdata = userdata;
595 G_CALLBACK(ui_menu_event_wrapper),
600 G_CALLBACK(ui_destroy_userdata),
604 gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget);
607 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);