#include "monolog.h" #include "zori.h" #include "zori_widget.h" #include "zori_caption.h" #include "zori_menu.h" /* Magic comment for runcprotoall: @generate_cproto@ */ struct zori_menu * zori_widget_to_menu(struct zori_widget * widget) { if (!zori_widget_is_type(widget, ZORI_WIDGET_TYPE_MENU)) return NULL; return ZORI_CONTAINER_OF(widget, struct zori_menu, widget); } struct zori_widget * zori_menu_get_selected(struct zori_menu * menu) { if (!menu) return NULL; if (menu->selected_index < 0) return NULL; return miao_unsafe_get(&menu->widget.children, menu->selected_index); } int zori_menu_select_index(struct zori_menu * menu, int index) { struct zori_widget * selected = NULL; size_t size = miao_size(&menu->widget.children); if (size < 1) return ZORI_HANDLE_ERROR; if (index < 0) return ZORI_HANDLE_DONE; if ((size_t)index >= size) return ZORI_HANDLE_DONE; menu->selected_index = index; selected = zori_menu_get_selected(menu); zori_mark_widget(selected); return ZORI_HANDLE_DONE; } int zori_menu_select_previous(struct zori_menu * menu) { size_t size = miao_size(&menu->widget.children); int new_selection = menu->selected_index - 1; /* "roll over" */ if (new_selection < 0) { new_selection = (int)size - 1; } return zori_menu_select_index(menu, new_selection); } int zori_menu_select_next(struct zori_menu * menu) { size_t size = miao_size(&menu->widget.children); int new_selection = menu->selected_index + 1; /* "roll over" */ if ((size_t)new_selection >= size) { new_selection = 0; } return zori_menu_select_index(menu, new_selection); } int zori_menu_select_first(struct zori_menu * menu) { return zori_menu_select_index(menu, 0); } int zori_menu_activate_selected(struct zori_menu * menu) { struct zori_widget * selected = zori_menu_get_selected(menu); if (selected) { LOG_NOTE("Item selected: %p!\n", selected); return zori_widget_raise_internal_action_event(selected); } LOG_WARNING("No item selected!\n"); return ZORI_HANDLE_IGNORE; } int zori_menu_close(struct zori_menu * menu) { struct zori_widget * parent; parent = menu->widget.parent; zori_widget_raise_close_event(parent, &menu->widget); zori_widget_active_(&menu->widget, false); zori_widget_visible_(&menu->widget, false); zori_widget_set_closed_result(&menu->widget, 1); return ZORI_HANDLE_DONE; } int zori_menu_on_child_close(union zori_event * event) { struct zori_widget * widget = event->any.widget; struct zori_menu * menu = zori_widget_to_menu(widget); zori_mark_widget(zori_menu_get_selected(menu)); return ZORI_HANDLE_DONE; } int zori_menu_on_key_down(union zori_event * event) { struct zori_widget * widget = event->any.widget; struct zori_menu * menu = zori_widget_to_menu(widget); struct zori_widget * item = NULL; if (miao_out_of_bounds(&menu->widget.children, menu->selected_index)) { return ZORI_HANDLE_IGNORE; } item = miao_unsafe_get(&widget->children, menu->selected_index); switch (event->sys.ev->keyboard.keycode) { case ALLEGRO_KEY_UP: return zori_menu_select_previous(menu); case ALLEGRO_KEY_DOWN: return zori_menu_select_next(menu); case ALLEGRO_KEY_ENTER: case ALLEGRO_KEY_SPACE: case ALLEGRO_KEY_LCTRL: case ALLEGRO_KEY_RCTRL: return zori_menu_activate_selected(menu); case ALLEGRO_KEY_BACKSPACE: case ALLEGRO_KEY_LSHIFT: case ALLEGRO_KEY_RSHIFT: return zori_menu_close(menu); default: return ZORI_HANDLE_IGNORE; } return ZORI_HANDLE_IGNORE; } int zori_menu_on_draw(union zori_event * event) { struct zori_widget * widget = event->any.widget; if (zori_widget_visible(widget)) { zori_widget_draw_background(widget); } return zori_widget_must_draw_children(widget); } struct zori_handler zori_menu_handlers[] = { { ZORI_SYSTEM_EVENT_KEY_DOWN, zori_menu_on_key_down , NULL}, { ZORI_EVENT_DRAW , zori_menu_on_draw , NULL}, { ZORI_EVENT_CLOSE , zori_menu_on_child_close , NULL}, }; struct zori_menu * zori_menu_init( struct zori_menu * menu, zori_id id, zori_id parent_id, zori_rebox * box, struct zori_style * style ) { struct zori_widget * parent = zori_get_widget(parent_id); if (!menu) return NULL; menu->selected_index = 0; zori_widget_initall(&menu->widget, ZORI_WIDGET_TYPE_MENU, id, parent, box, style, ZORI_ARRAY_AND_AMOUNT( zori_menu_handlers)); zori_widget_hover_(&menu->widget, false); return menu; } struct zori_menu * zori_menu_new(zori_id id, zori_id parent_id, zori_box * box) { struct zori_menu * menu = NULL; menu = calloc(1, sizeof(*menu)); if (!menu) return NULL; if (!zori_menu_init(menu, id, parent_id, box, NULL)) { free(menu); return NULL; } return menu; } zori_id zori_new_menu(zori_id id, zori_id parent, zori_box * box) { struct zori_menu * menu = zori_menu_new(id, parent, box); if (!menu) return ZORI_ID_ENOMEM; return menu->widget.id; }