src/util/gui/menu.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "menu.h"
7
8#include "util/gui.h"
9#include "util/gui/font.h"
10
11DEFINE_VECTOR(GUIMenuItemList, struct GUIMenuItem);
12
13enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem* item) {
14 size_t start = 0;
15 size_t lineHeight = GUIFontHeight(params->font);
16 size_t pageSize = params->height / lineHeight;
17 if (pageSize > 4) {
18 pageSize -= 4;
19 } else {
20 pageSize = 1;
21 }
22 int cursorOverItem = 0;
23
24 GUIInvalidateKeys(params);
25 while (true) {
26 uint32_t newInput = 0;
27 GUIPollInput(params, &newInput, 0);
28 int cx, cy;
29 enum GUICursorState cursor = GUIPollCursor(params, &cx, &cy);
30
31 if (newInput & (1 << GUI_INPUT_UP) && menu->index > 0) {
32 --menu->index;
33 }
34 if (newInput & (1 << GUI_INPUT_DOWN) && menu->index < GUIMenuItemListSize(&menu->items) - 1) {
35 ++menu->index;
36 }
37 if (newInput & (1 << GUI_INPUT_LEFT)) {
38 if (menu->index >= pageSize) {
39 menu->index -= pageSize;
40 } else {
41 menu->index = 0;
42 }
43 }
44 if (newInput & (1 << GUI_INPUT_RIGHT)) {
45 if (menu->index + pageSize < GUIMenuItemListSize(&menu->items)) {
46 menu->index += pageSize;
47 } else {
48 menu->index = GUIMenuItemListSize(&menu->items) - 1;
49 }
50 }
51 if (cursor != GUI_CURSOR_NOT_PRESENT) {
52 int index = (cy / lineHeight) - 2;
53 if (index >= 0 && index + start < GUIMenuItemListSize(&menu->items)) {
54 if (menu->index != index + start || !cursorOverItem) {
55 cursorOverItem = 1;
56 }
57 menu->index = index + start;
58 } else {
59 cursorOverItem = 0;
60 }
61 }
62
63 if (menu->index < start) {
64 start = menu->index;
65 }
66 while ((menu->index - start + 4) * lineHeight > params->height) {
67 ++start;
68 }
69 if (newInput & (1 << GUI_INPUT_CANCEL)) {
70 break;
71 }
72 if (newInput & (1 << GUI_INPUT_SELECT) || (cursorOverItem == 2 && cursor == GUI_CURSOR_CLICKED)) {
73 *item = *GUIMenuItemListGetPointer(&menu->items, menu->index);
74 if (item->submenu) {
75 enum GUIMenuExitReason reason = GUIShowMenu(params, item->submenu, item);
76 if (reason != GUI_MENU_EXIT_BACK) {
77 return reason;
78 }
79 } else {
80 return GUI_MENU_EXIT_ACCEPT;
81 }
82 }
83 if ((cursorOverItem == 1 && cursor == GUI_CURSOR_UP)) {
84 cursorOverItem = 2;
85 }
86 if (newInput & (1 << GUI_INPUT_BACK)) {
87 return GUI_MENU_EXIT_BACK;
88 }
89
90 params->drawStart();
91 if (menu->background) {
92 menu->background->draw(menu->background, GUIMenuItemListGetPointer(&menu->items, menu->index)->data);
93 }
94 if (params->guiPrepare) {
95 params->guiPrepare();
96 }
97 unsigned y = lineHeight;
98 GUIFontPrint(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, menu->title);
99 y += 2 * lineHeight;
100 size_t i;
101 for (i = start; i < GUIMenuItemListSize(&menu->items); ++i) {
102 int color = 0xE0A0A0A0;
103 char bullet = ' ';
104 if (i == menu->index) {
105 color = 0xFFFFFFFF;
106 bullet = '>';
107 }
108 GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, GUIMenuItemListGetPointer(&menu->items, i)->title);
109 y += lineHeight;
110 if (y + lineHeight > params->height) {
111 break;
112 }
113 }
114 if (params->guiFinish) {
115 params->guiFinish();
116 }
117 params->drawEnd();
118 }
119 return GUI_MENU_EXIT_CANCEL;
120}