zori_menu.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "zori.h"
  2. #include "zori_widget.h"
  3. #include "zori_caption.h"
  4. #include "zori_menu.h"
  5. struct zori_menu * zori_widget_to_menu(struct zori_widget * widget) {
  6. if (!zori_widget_is_type(widget, ZORI_WIDGET_TYPE_MENU)) return NULL;
  7. return ZORI_CONTAINER_OF(widget, struct zori_menu, widget);
  8. }
  9. struct zori_widget * zori_menu_get_selected(struct zori_menu * menu) {
  10. if (!menu) return NULL;
  11. if (menu->selected_index < 0) return NULL;
  12. return miao_unsafe_get(&menu->widget.children, menu->selected_index);
  13. }
  14. int zori_menu_select_index(struct zori_menu * menu, int index) {
  15. struct zori_widget * selected = NULL;
  16. size_t size = miao_size(&menu->widget.children);
  17. if (size < 1) return ZORI_HANDLE_ERROR;
  18. if (index < 0) return ZORI_HANDLE_DONE;
  19. if ((size_t)index >= size) return ZORI_HANDLE_DONE;
  20. menu->selected_index = index;
  21. selected = zori_menu_get_selected(menu);
  22. zori_mark_widget(selected);
  23. return ZORI_HANDLE_DONE;
  24. }
  25. int zori_menu_select_previous(struct zori_menu * menu) {
  26. size_t size = miao_size(&menu->widget.children);
  27. int new_selection = menu->selected_index - 1;
  28. /* "roll over" */
  29. if (new_selection < 0) {
  30. new_selection = (int)size - 1;
  31. }
  32. return zori_menu_select_index(menu, new_selection);
  33. }
  34. int zori_menu_select_next(struct zori_menu * menu) {
  35. size_t size = miao_size(&menu->widget.children);
  36. int new_selection = menu->selected_index + 1;
  37. /* "roll over" */
  38. if ((size_t)new_selection >= size) {
  39. new_selection = 0;
  40. }
  41. return zori_menu_select_index(menu, new_selection);
  42. }
  43. int zori_menu_select_first(struct zori_menu * menu) {
  44. return zori_menu_select_index(menu, 0);
  45. }
  46. int zori_menu_activate_selected(struct zori_menu * menu) {
  47. struct zori_widget * selected = zori_menu_get_selected(menu);
  48. if (selected) {
  49. return zori_widget_raise_action_event(selected);
  50. }
  51. return ZORI_HANDLE_IGNORE;
  52. }
  53. int zori_menu_close(struct zori_menu * menu) {
  54. struct zori_widget * parent;
  55. parent = menu->widget.parent;
  56. zori_widget_raise_close_event(parent, &menu->widget);
  57. zori_widget_active_(&menu->widget, false);
  58. return ZORI_HANDLE_DONE;
  59. }
  60. int zori_menu_on_child_close(union zori_event * event) {
  61. struct zori_widget * widget = event->any.widget;
  62. struct zori_menu * menu = zori_widget_to_menu(widget);
  63. zori_mark_widget(zori_menu_get_selected(menu));
  64. return ZORI_HANDLE_DONE;
  65. }
  66. int zori_menu_on_key_down(union zori_event * event) {
  67. struct zori_widget * widget = event->any.widget;
  68. struct zori_menu * menu = zori_widget_to_menu(widget);
  69. struct zori_widget * item = NULL;
  70. if (miao_out_of_bounds(&menu->widget.children, menu->selected_index)) {
  71. return ZORI_HANDLE_IGNORE;
  72. }
  73. item = miao_unsafe_get(&widget->children, menu->selected_index);
  74. switch (event->sys.ev->keyboard.keycode) {
  75. case ALLEGRO_KEY_UP:
  76. return zori_menu_select_previous(menu);
  77. case ALLEGRO_KEY_DOWN:
  78. return zori_menu_select_next(menu);
  79. case ALLEGRO_KEY_ENTER:
  80. case ALLEGRO_KEY_SPACE:
  81. case ALLEGRO_KEY_LCTRL:
  82. case ALLEGRO_KEY_RCTRL:
  83. return zori_menu_activate_selected(menu);
  84. case ALLEGRO_KEY_BACKSPACE:
  85. case ALLEGRO_KEY_LSHIFT:
  86. case ALLEGRO_KEY_RSHIFT:
  87. return zori_menu_close(menu);
  88. default:
  89. return ZORI_HANDLE_IGNORE;
  90. }
  91. return ZORI_HANDLE_IGNORE;
  92. }
  93. int zori_menu_on_draw(union zori_event * event) {
  94. struct zori_widget * widget = event->any.widget;
  95. zori_widget_draw_background(widget);
  96. return ZORI_HANDLE_PASS;
  97. }
  98. struct zori_handler zori_menu_handlers[] = {
  99. { ZORI_SYSTEM_EVENT_KEY_DOWN, zori_menu_on_key_down , NULL},
  100. { ZORI_EVENT_DRAW , zori_menu_on_draw , NULL},
  101. { ZORI_EVENT_CLOSE , zori_menu_on_child_close , NULL},
  102. };
  103. struct zori_menu * zori_menu_init(
  104. struct zori_menu * menu, zori_id id, zori_id parent_id,
  105. zori_rebox * box, struct zori_style * style
  106. ) {
  107. struct zori_widget * parent = zori_get_widget(parent_id);
  108. if (!menu) return NULL;
  109. menu->selected_index = 0;
  110. zori_widget_initall(&menu->widget, ZORI_WIDGET_TYPE_MENU, id, parent, box, style,
  111. ZORI_ARRAY_AND_AMOUNT( zori_menu_handlers));
  112. zori_widget_hover_(&menu->widget, false);
  113. return menu;
  114. }
  115. struct zori_menu * zori_menu_new(zori_id id, zori_id parent_id, zori_box * box) {
  116. struct zori_menu * menu = NULL;
  117. menu = calloc(1, sizeof(*menu));
  118. if (!menu) return NULL;
  119. if (!zori_menu_init(menu, id, parent_id, box, NULL)) {
  120. free(menu);
  121. return NULL;
  122. }
  123. return menu;
  124. }
  125. zori_id zori_new_menu(zori_id id, zori_id parent, zori_box * box) {
  126. struct zori_menu * menu = zori_menu_new(id, parent, box);
  127. if (!menu) return ZORI_ID_ENOMEM;
  128. return menu->widget.id;
  129. }