all repos — mgba @ 4cf016d442f966605d818f9fee26b375dcebac35

mGBA Game Boy Advance Emulator

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}