all repos — mgba @ 4cf016d442f966605d818f9fee26b375dcebac35

mGBA Game Boy Advance Emulator

GUI: Support for touch/cursor
Jeffrey Pfau jeffrey@endrift.com
Fri, 04 Sep 2015 22:50:20 -0700
commit

4cf016d442f966605d818f9fee26b375dcebac35

parent

2dcefe8fa5d1beb835e822ae2fc0eac216972942

M src/platform/3ds/main.csrc/platform/3ds/main.c

@@ -235,6 +235,18 @@ }

return keys; } +static enum GUICursorState _pollCursor(int* x, int* y) { + hidScanInput(); + if (!(hidKeysHeld() & KEY_TOUCH)) { + return GUI_CURSOR_UP; + } + touchPosition pos; + hidTouchRead(&pos); + *x = pos.px; + *y = pos.py; + return GUI_CURSOR_DOWN; +} + static void _sampleRotation(struct GBARotationSource* source) { struct GBA3DSRotationSource* rotation = (struct GBA3DSRotationSource*) source; // Work around ctrulib getting the entries wrong

@@ -322,7 +334,8 @@ struct GBAGUIRunner runner = {

.params = { 320, 240, font, "/", - _drawStart, _drawEnd, _pollInput, + _drawStart, _drawEnd, + _pollInput, _pollCursor, 0, 0, GUI_PARAMS_TRAIL
M src/platform/psp2/CMakeLists.txtsrc/platform/psp2/CMakeLists.txt

@@ -5,7 +5,7 @@

list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sce-vfs.c) set(VFS_SRC ${VFS_SRC} PARENT_SCOPE) -set(OS_LIB -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lSceMotion_stub -lScePower_stub -lpng -lz -l${M_LIBRARY}) +set(OS_LIB -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lSceMotion_stub -lScePower_stub -lSceTouch_stub -lpng -lz -l${M_LIBRARY}) set(OBJCOPY_CMD ${OBJCOPY} -I binary -O elf32-littlearm -B arm) list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c)
M src/platform/psp2/main.csrc/platform/psp2/main.c

@@ -15,6 +15,7 @@ #include <psp2/ctrl.h>

#include <psp2/kernel/processmgr.h> #include <psp2/kernel/threadmgr.h> #include <psp2/moduleinfo.h> +#include <psp2/touch.h> #include <vita2d.h>

@@ -63,15 +64,27 @@

return input; } -int main() { - printf("%s initializing", projectName); +static enum GUICursorState _pollCursor(int* x, int* y) { + SceTouchData touch; + sceTouchPeek(0, &touch, 1); + if (touch.reportNum < 1) { + return GUI_CURSOR_UP; + } + *x = touch.report[0].x / 2; + *y = touch.report[0].y / 2; + return GUI_CURSOR_DOWN; +} + +int main() { vita2d_init(); struct GUIFont* font = GUIFontCreate(); struct GBAGUIRunner runner = { .params = { PSP2_HORIZONTAL_PIXELS, PSP2_VERTICAL_PIXELS, - font, "cache0:", _drawStart, _drawEnd, _pollInput, 0, 0, + font, "cache0:", _drawStart, _drawEnd, + _pollInput, _pollCursor, + 0, 0, GUI_PARAMS_TRAIL },
M src/platform/wii/main.csrc/platform/wii/main.c

@@ -34,6 +34,7 @@

static void _drawStart(void); static void _drawEnd(void); static uint32_t _pollInput(void); +static enum GUICursorState _pollCursor(int* x, int* y); static void _guiPrepare(void); static void _guiFinish(void);

@@ -68,6 +69,7 @@ int main() {

VIDEO_Init(); PAD_Init(); WPAD_Init(); + WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC_IR); AUDIO_Init(0); AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); AUDIO_RegisterDMACallback(_audioDMA);

@@ -159,7 +161,8 @@ struct GBAGUIRunner runner = {

.params = { 352, 230, font, "/", - _drawStart, _drawEnd, _pollInput, + _drawStart, _drawEnd, + _pollInput, _pollCursor, _guiPrepare, _guiFinish, GUI_PARAMS_TRAIL

@@ -254,7 +257,7 @@ if ((padkeys & PAD_BUTTON_A) || (wiiPad & WPAD_BUTTON_2) ||

((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_A | WPAD_CLASSIC_BUTTON_Y)))) { keys |= 1 << GUI_INPUT_SELECT; } - if ((padkeys & PAD_BUTTON_B) || (wiiPad & WPAD_BUTTON_1) || + if ((padkeys & PAD_BUTTON_B) || (wiiPad & WPAD_BUTTON_1) || (wiiPad & WPAD_BUTTON_B) || ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_X)))) { keys |= 1 << GUI_INPUT_BACK; }

@@ -281,6 +284,22 @@ }

return keys; } +static enum GUICursorState _pollCursor(int* x, int* y) { + ir_t ir; + WPAD_IR(0, &ir); + if (!ir.smooth_valid) { + return GUI_CURSOR_NOT_PRESENT; + } + *x = ir.sx; + *y = ir.sy; + WPAD_ScanPads(); + u32 wiiPad = WPAD_ButtonsHeld(0); + if (wiiPad & WPAD_BUTTON_A) { + return GUI_CURSOR_DOWN; + } + return GUI_CURSOR_UP; +} + void _guiPrepare(void) { Mtx44 proj; guOrtho(proj, -20, 240, 0, 352, 0, 300);

@@ -324,7 +343,6 @@ AUDIO_StopDMA();

} void _gameLoaded(struct GBAGUIRunner* runner) { - WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC); if (runner->context.gba->memory.hw.devices & HW_GYRO) { int i; for (i = 0; i < 6; ++i) {
M src/util/gui.csrc/util/gui.c

@@ -31,6 +31,37 @@ *heldInput = input;

} } +enum GUICursorState GUIPollCursor(struct GUIParams* params, int* x, int* y) { + if (!params->pollCursor) { + return GUI_CURSOR_NOT_PRESENT; + } + enum GUICursorState state = params->pollCursor(x, y); + if (params->cursorState == GUI_CURSOR_DOWN) { + int dragX = *x - params->cx; + int dragY = *y - params->cy; + if (dragX * dragX + dragY * dragY > 25) { + params->cursorState = GUI_CURSOR_DRAGGING; + return GUI_CURSOR_DRAGGING; + } + if (state == GUI_CURSOR_UP) { + params->cursorState = GUI_CURSOR_UP; + return GUI_CURSOR_CLICKED; + } + } else { + params->cx = *x; + params->cy = *y; + } + if (params->cursorState == GUI_CURSOR_DRAGGING) { + if (state == GUI_CURSOR_UP || state == GUI_CURSOR_NOT_PRESENT) { + params->cursorState = GUI_CURSOR_UP; + return GUI_CURSOR_UP; + } + return GUI_CURSOR_DRAGGING; + } + params->cursorState = state; + return params->cursorState; +} + void GUIInvalidateKeys(struct GUIParams* params) { for (int i = 0; i < GUI_INPUT_MAX; ++i) { params->inputHistory[i] = 0;
M src/util/gui.hsrc/util/gui.h

@@ -28,6 +28,14 @@

GUI_INPUT_MAX = 0x20 }; +enum GUICursorState { + GUI_CURSOR_NOT_PRESENT, + GUI_CURSOR_UP, + GUI_CURSOR_DOWN, + GUI_CURSOR_CLICKED, + GUI_CURSOR_DRAGGING +}; + struct GUIBackground { void (*draw)(struct GUIBackground*, void* context); };

@@ -41,21 +49,25 @@

void (*drawStart)(void); void (*drawEnd)(void); uint32_t (*pollInput)(void); + enum GUICursorState (*pollCursor)(int* x, int* y); void (*guiPrepare)(void); void (*guiFinish)(void); // State int inputHistory[GUI_INPUT_MAX]; + enum GUICursorState cursorState; + int cx, cy; // Directories char currentPath[PATH_MAX]; size_t fileIndex; }; -#define GUI_PARAMS_TRAIL {}, "", 0 +#define GUI_PARAMS_TRAIL {}, GUI_CURSOR_NOT_PRESENT, 0, 0, "", 0 void GUIInit(struct GUIParams* params); void GUIPollInput(struct GUIParams* params, uint32_t* newInput, uint32_t* heldInput); +enum GUICursorState GUIPollCursor(struct GUIParams* params, int* x, int* y); void GUIInvalidateKeys(struct GUIParams* params); #endif
M src/util/gui/menu.csrc/util/gui/menu.c

@@ -12,17 +12,21 @@ DEFINE_VECTOR(GUIMenuItemList, struct GUIMenuItem);

enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem* item) { size_t start = 0; - size_t pageSize = params->height / GUIFontHeight(params->font); + size_t lineHeight = GUIFontHeight(params->font); + size_t pageSize = params->height / lineHeight; if (pageSize > 4) { pageSize -= 4; } else { pageSize = 1; } + int cursorOverItem = 0; GUIInvalidateKeys(params); while (true) { uint32_t newInput = 0; GUIPollInput(params, &newInput, 0); + int cx, cy; + enum GUICursorState cursor = GUIPollCursor(params, &cx, &cy); if (newInput & (1 << GUI_INPUT_UP) && menu->index > 0) { --menu->index;

@@ -42,19 +46,30 @@ if (menu->index + pageSize < GUIMenuItemListSize(&menu->items)) {

menu->index += pageSize; } else { menu->index = GUIMenuItemListSize(&menu->items) - 1; + } + } + if (cursor != GUI_CURSOR_NOT_PRESENT) { + int index = (cy / lineHeight) - 2; + if (index >= 0 && index + start < GUIMenuItemListSize(&menu->items)) { + if (menu->index != index + start || !cursorOverItem) { + cursorOverItem = 1; + } + menu->index = index + start; + } else { + cursorOverItem = 0; } } if (menu->index < start) { start = menu->index; } - while ((menu->index - start + 4) * GUIFontHeight(params->font) > params->height) { + while ((menu->index - start + 4) * lineHeight > params->height) { ++start; } if (newInput & (1 << GUI_INPUT_CANCEL)) { break; } - if (newInput & (1 << GUI_INPUT_SELECT)) { + if (newInput & (1 << GUI_INPUT_SELECT) || (cursorOverItem == 2 && cursor == GUI_CURSOR_CLICKED)) { *item = *GUIMenuItemListGetPointer(&menu->items, menu->index); if (item->submenu) { enum GUIMenuExitReason reason = GUIShowMenu(params, item->submenu, item);

@@ -65,6 +80,9 @@ } else {

return GUI_MENU_EXIT_ACCEPT; } } + if ((cursorOverItem == 1 && cursor == GUI_CURSOR_UP)) { + cursorOverItem = 2; + } if (newInput & (1 << GUI_INPUT_BACK)) { return GUI_MENU_EXIT_BACK; }

@@ -76,9 +94,9 @@ }

if (params->guiPrepare) { params->guiPrepare(); } - unsigned y = GUIFontHeight(params->font); + unsigned y = lineHeight; GUIFontPrint(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, menu->title); - y += 2 * GUIFontHeight(params->font); + y += 2 * lineHeight; size_t i; for (i = start; i < GUIMenuItemListSize(&menu->items); ++i) { int color = 0xE0A0A0A0;

@@ -88,16 +106,14 @@ color = 0xFFFFFFFF;

bullet = '>'; } GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, GUIMenuItemListGetPointer(&menu->items, i)->title); - y += GUIFontHeight(params->font); - if (y + GUIFontHeight(params->font) > params->height) { + y += lineHeight; + if (y + lineHeight > params->height) { break; } } if (params->guiFinish) { params->guiFinish(); } - y += GUIFontHeight(params->font) * 2; - params->drawEnd(); } return GUI_MENU_EXIT_CANCEL;