--- a/ui/gtk/menu.c Sun May 23 09:44:43 2021 +0200 +++ b/ui/gtk/menu.c Sat Jan 04 16:38:48 2025 +0100 @@ -34,189 +34,58 @@ #include "menu.h" #include "toolkit.h" #include "../common/context.h" +#include "../common/menu.h" +#include "../common/types.h" #include "../ui/properties.h" #include "../ui/window.h" #include "container.h" -static UcxList *menus; -static UcxList *current; - -void ui_menu(char *label) { - // free current menu hierarchy - ucx_list_free(current); - - // create menu - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items = NULL; - menu->parent = NULL; - - current = ucx_list_prepend(NULL, menu); - menus = ucx_list_append(menus, menu); - -} - -void ui_submenu(char *label) { - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items = NULL; - menu->parent = NULL; - - // add submenu to current menu - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, menu); - - // set the submenu to current menu - current = ucx_list_prepend(current, menu); -} +#include <cx/linked_list.h> +#include <cx/array_list.h> -void ui_submenu_end() { - if(ucx_list_size(current) < 2) { - return; - } - current = ucx_list_remove(current, current); - //UcxList *c = current; -} - -void ui_menuitem(char *label, ui_callback f, void *userdata) { - ui_menuitem_gr(label, f, userdata, -1); -} - -void ui_menuitem_st(char *stockid, ui_callback f, void *userdata) { - ui_menuitem_stgr(stockid, f, userdata, -1); -} - -void ui_menuitem_gr(char *label, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiMenuItem *item = malloc(sizeof(UiMenuItem)); - item->item.add_to = (ui_menu_add_f)add_menuitem_widget; - - item->label = label; - item->userdata = userdata; - item->callback = f; - item->groups = NULL; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group); - } - va_end(ap); - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} +#if GTK_MAJOR_VERSION <= 3 -void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiStMenuItem *item = malloc(sizeof(UiStMenuItem)); - item->item.add_to = (ui_menu_add_f)add_menuitem_st_widget; - - item->stockid = stockid; - item->userdata = userdata; - item->callback = f; - item->groups = NULL; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group); - } - va_end(ap); - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_menuseparator() { - if(!current) { - return; - } - - UiMenuItemI *item = malloc(sizeof(UiMenuItemI)); - item->add_to = (ui_menu_add_f)add_menuseparator_widget; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_checkitem(char *label, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiCheckItem *item = malloc(sizeof(UiCheckItem)); - item->item.add_to = (ui_menu_add_f)add_checkitem_widget; - item->label = label; - item->callback = f; - item->userdata = userdata; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_checkitem_nv(char *label, char *vname) { - if(!current) { - return; - } - - UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); - item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget; - item->varname = vname; - item->label = label; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiMenuItemList *item = malloc(sizeof(UiMenuItemList)); - item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget; - item->callback = f; - item->userdata = userdata; - item->list = items; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} +static ui_menu_add_f createMenuItem[] = { + /* UI_MENU */ add_menu_widget, + /* UI_MENU_ITEM */ add_menuitem_widget, + /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, + /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_SEPARATOR */ add_menuseparator_widget +}; // private menu functions GtkWidget *ui_create_menubar(UiObject *obj) { - if(menus == NULL) { + UiMenu *menus_begin = uic_get_menu_list(); + if(menus_begin == NULL) { return NULL; } GtkWidget *mb = gtk_menu_bar_new(); - UcxList *ls = menus; + UiMenu *ls = menus_begin; while(ls) { - UiMenu *menu = ls->data; - menu->item.add_to(mb, 0, &menu->item, obj); + UiMenu *menu = ls; + add_menu_widget(mb, 0, &menu->item, obj); - ls = ls->next; + ls = (UiMenu*)ls->item.next; } return mb; } +void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it, obj); + it = it->next; + index++; + } +} + void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) { UiMenu *menu = (UiMenu*)item; @@ -224,15 +93,8 @@ GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget); - UcxList *ls = menu->items; - int index = 0; - while(ls) { - UiMenuItemI *i = ls->data; - i->add_to(menu_widget, index, i, obj); - - ls = ls->next; - index++; - } + ui_add_menu_items(menu_widget, i, menu, obj); + gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item); } @@ -249,6 +111,7 @@ event->userdata = i->userdata; event->callback = i->callback; event->value = 0; + event->customdata = NULL; g_signal_connect( widget, @@ -265,10 +128,14 @@ gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); if(i->groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); + CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups); + cxListAddArray(groups, i->groups, i->ngroups); + uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); + cxListDestroy(groups); } } +/* void add_menuitem_st_widget( GtkWidget *parent, int index, @@ -304,6 +171,7 @@ uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); } } +*/ void add_menuseparator_widget( GtkWidget *parent, @@ -317,7 +185,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); @@ -327,7 +195,8 @@ event->userdata = ci->userdata; event->callback = ci->callback; event->value = 0; - + event->customdata = NULL; + g_signal_connect( widget, "toggled", @@ -341,6 +210,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); @@ -357,27 +231,31 @@ // TODO: error } } +*/ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; - UcxMempool *mp = obj->ctx->mempool; + const CxAllocator *a = obj->ctx->allocator; - UiActiveMenuItemList *ls = ucx_mempool_malloc( - mp, + UiActiveMenuItemList *ls = cxMalloc( + a, sizeof(UiActiveMenuItemList)); ls->object = obj; ls->menu = GTK_MENU_SHELL(p); ls->index = index; ls->oldcount = 0; - ls->list = il->list; + ls->getvalue = il->getvalue; + + UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + ls->list = var->value; + ls->callback = il->callback; ls->userdata = il->userdata; - ls->list->observers = ui_add_observer( - ls->list->observers, - (ui_callback)ui_update_menuitem_list, - ls); + UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls); + ls->list->observers = ui_obsvlist_add(ls->list->observers, observer); + uic_list_register_observer_destructor(obj->ctx, ls->list, observer); ui_update_menuitem_list(NULL, ls); } @@ -398,25 +276,29 @@ } } - char *str = ui_list_first(list->list); - if(str) { + void* elm = ui_list_first(list->list); + if(elm) { GtkWidget *widget = gtk_separator_menu_item_new(); gtk_menu_shell_insert(list->menu, widget, list->index); gtk_widget_show(widget); } + + ui_getvaluefunc getvalue = list->getvalue; int i = 1; - while(str) { - GtkWidget *widget = gtk_menu_item_new_with_label(str); + while(elm) { + char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + + GtkWidget *widget = gtk_menu_item_new_with_label(label); gtk_menu_shell_insert(list->menu, widget, list->index + i); gtk_widget_show(widget); if(list->callback) { - // TODO: use mempool UiEventData *event = malloc(sizeof(UiEventData)); event->obj = list->object; event->userdata = list->userdata; event->callback = list->callback; event->value = i - 1; + event->customdata = elm; g_signal_connect( widget, @@ -430,7 +312,7 @@ event); } - str = ui_list_next(list->list); + elm = ui_list_next(list->list); i++; } @@ -442,7 +324,7 @@ evt.obj = event->obj; evt.window = event->obj->window; evt.document = event->obj->ctx->document; - evt.eventdata = NULL; + evt.eventdata = event->customdata; evt.intval = event->value; event->callback(&evt, event->userdata); } @@ -473,34 +355,28 @@ * widget menu functions */ +UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget) { + GtkWidget *menu_widget = gtk_menu_new(); + ui_add_menu_items(menu_widget, 0, builder->menus_begin, obj); + return GTK_MENU(menu_widget); +} + static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { if(event->type == GDK_BUTTON_PRESS) { GdkEventButton *e = (GdkEventButton*)event; if(e->button == 3) { gtk_widget_show_all(GTK_WIDGET(menu)); - ui_contextmenu_popup(menu); - return TRUE; + ui_contextmenu_popup(menu, widget, 0, 0); } } return FALSE; } -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - return ui_contextmenu_w(obj, ct->current); +void ui_widget_set_contextmenu(GtkWidget *widget, GtkMenu *menu) { + g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); } -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - GtkMenu *menu = GTK_MENU(gtk_menu_new()); - g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); - - ct->menu = menu; - return menu; -} - -void ui_contextmenu_popup(UIMENU menu) { +void ui_contextmenu_popup(UIMENU menu, GtkWidget *widget, int x, int y) { #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16 gtk_menu_popup_at_pointer(menu, NULL); #else @@ -508,102 +384,255 @@ #endif } -void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { - ui_widget_menuitem_gr(obj, label, f, userdata, -1); +#endif /* GTK_MAJOR_VERSION <= 3 */ + + + +#if GTK_MAJOR_VERSION >= 4 + + + +static ui_gmenu_add_f createMenuItem[] = { + /* UI_MENU */ ui_gmenu_add_menu, + /* UI_MENU_ITEM */ ui_gmenu_add_menuitem, + /* UI_MENU_CHECK_ITEM */ ui_gmenu_add_checkitem, + /* UI_MENU_RADIO_ITEM */ ui_gmenu_add_radioitem, + /* UI_MENU_ITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_CHECKITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_RADIOITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_SEPARATOR */ ui_gmenu_add_menuseparator +}; + +void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + int index_section = 0; + GMenu *section = NULL; + while(it) { + if(it->type == UI_MENU_SEPARATOR) { + section = g_menu_new(); + g_menu_append_section(parent, NULL, G_MENU_MODEL(section)); + index++; + index_section = 0; + } else { + if(section) { + createMenuItem[it->type](section, index_section++, it, obj); + } else { + createMenuItem[it->type](parent, index++, it, obj); + } + } + it = it->next; + } } -void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; +void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenu *mi = (UiMenu*)item; + GMenu *menu = g_menu_new(); + ui_gmenu_add_menu_items(menu, 0, mi, obj); + g_menu_append_submenu(parent, mi->label, G_MENU_MODEL(menu)); +} + +static void action_enable(GSimpleAction *action, int enabled) { + g_simple_action_set_enabled(action, enabled); +} + +void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *i = (UiMenuItem*)item; + + GSimpleAction *action = g_simple_action_new(item->id, NULL); + g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); + + if(i->groups) { + CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups); + cxListAddArray(groups, i->groups, i->ngroups); + uic_add_group_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups); + cxListDestroy(groups); } - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); - } - va_end(ap); - - // create menuitem - GtkWidget *widget = gtk_menu_item_new_with_mnemonic(label); - gtk_widget_show(widget); - - if(f) { + if(i->callback != NULL) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; - event->userdata = userdata; - event->callback = f; + event->userdata = i->userdata; + event->callback = i->callback; event->value = 0; + event->customdata = NULL; g_signal_connect( - widget, + action, "activate", - G_CALLBACK(ui_menu_event_wrapper), + G_CALLBACK(ui_activate_event_wrapper), event); g_signal_connect( - widget, + obj->widget, "destroy", G_CALLBACK(ui_destroy_userdata), event); } - gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); + char action_name[32]; + snprintf(action_name, 32, "win.%s", item->id); + g_menu_append(parent, i->label, action_name); +} + +void ui_gmenu_add_menuseparator(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { - if(groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); - } +} + +void ui_gmenu_add_checkitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item; + + // TODO +} + +void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + } -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); +void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuItemList *il = (UiMenuItemList*)item; + + const CxAllocator *a = obj->ctx->allocator; + + UiActiveGMenuItemList *ls = cxMalloc( + a, + sizeof(UiActiveGMenuItemList)); + + ls->object = obj; + ls->menu = p; + ls->index = index; + ls->oldcount = 0; + ls->getvalue = il->getvalue; + + UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + ls->var = var; + UiList *list = var->value; + + ls->callback = il->callback; + ls->userdata = il->userdata; + + UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls); + list->observers = ui_obsvlist_add(list->observers, observer); + uic_list_register_observer_destructor(obj->ctx, list, observer); + + GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i")); + g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); + snprintf(ls->action, 32, "win.%s", item->id); + + + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = il->userdata; + event->callback = il->callback; + event->customdata = var; + event->value = 0; + + g_signal_connect( + action, + "activate", + G_CALLBACK(ui_menu_list_item_activate_event_wrapper), + event); + g_signal_connect( + obj->widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + + ui_update_gmenu_item_list(NULL, ls); } -void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; +void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { + int intval = event->value; + if(parameter && g_variant_is_of_type(parameter, G_VARIANT_TYPE_INT32)) { + intval = g_variant_get_int32(parameter); } - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = event->customdata; + evt.intval = intval; + event->callback(&evt, event->userdata); +} + +void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { + int index = g_variant_get_int32(parameter); + UiVar *var = event->customdata; + UiList *list = var->value; + + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = ui_list_get(list, index); + evt.intval = index; + event->callback(&evt, event->userdata); + +} + +void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) { + // remove old items + for(int i=0;i<list->oldcount;i++) { + g_menu_remove(list->menu, list->index); } - va_end(ap); - - // create menuitem - GtkWidget *widget = gtk_image_menu_item_new_from_stock(stockid, obj->ctx->accel_group); - gtk_widget_show(widget); + UiList *ls = list->var->value; - if(f) { - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = obj; - event->userdata = userdata; - event->callback = f; - event->value = 0; + // add list items + ui_getvaluefunc getvalue = list->getvalue; + int i = 0; + void* elm = ui_list_first(ls); + while(elm) { + char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + + GMenuItem *item = g_menu_item_new(label, NULL); + GVariant *v = g_variant_new("i", i); + g_menu_item_set_action_and_target_value(item, list->action, v); + g_menu_insert_item(list->menu, list->index+i, item); + + elm = ui_list_next(ls); + i++; + } + + list->oldcount = i; +} - g_signal_connect( - widget, - "activate", - G_CALLBACK(ui_menu_event_wrapper), - event); - g_signal_connect( + +/* --------------------- context menu / menubuilder --------------------- */ + +static void remove_popover(GtkWidget *object, GtkPopoverMenu *menu) { + gtk_widget_unparent(GTK_WIDGET(menu)); +} + +UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, GtkWidget *widget) { + GMenu *menu = g_menu_new(); + ui_gmenu_add_menu_items(menu, 0, builder->menus_begin, obj); + GtkWidget *contextmenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu)); + gtk_popover_set_has_arrow(GTK_POPOVER(contextmenu), FALSE); + gtk_widget_set_halign(contextmenu, GTK_ALIGN_START); + gtk_widget_set_parent(GTK_WIDGET(contextmenu), widget); + g_signal_connect( widget, "destroy", - G_CALLBACK(ui_destroy_userdata), - event); - } - - gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); - - if(groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); - } + G_CALLBACK(remove_popover), + contextmenu); + return GTK_POPOVER_MENU(contextmenu); +} + +static void gesture_button_press(GtkGestureClick *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { + gtk_popover_set_pointing_to(GTK_POPOVER(user_data), &(GdkRectangle){ x, y, 0, 0 }); + gtk_popover_popup(GTK_POPOVER(user_data)); } + +void ui_widget_set_contextmenu(GtkWidget *widget, GtkPopoverMenu *menu) { + GtkGesture *gesture = gtk_gesture_click_new(); + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3); + gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); + g_signal_connect(gesture, "pressed", G_CALLBACK(gesture_button_press), menu); +} + +void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y) { + gtk_popover_set_pointing_to(GTK_POPOVER(menu), &(GdkRectangle){ x, y, 0, 0 }); + gtk_popover_popup(GTK_POPOVER(menu)); +} + +#endif