From 4cf016d442f966605d818f9fee26b375dcebac35 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 4 Sep 2015 22:50:20 -0700 Subject: [PATCH] GUI: Support for touch/cursor --- src/platform/3ds/main.c | 15 +++++++++++++- src/platform/psp2/CMakeLists.txt | 2 +- src/platform/psp2/main.c | 19 +++++++++++++++--- src/platform/wii/main.c | 24 +++++++++++++++++++--- src/util/gui.c | 31 +++++++++++++++++++++++++++++ src/util/gui.h | 14 ++++++++++++- src/util/gui/menu.c | 34 +++++++++++++++++++++++--------- 7 files changed, 121 insertions(+), 18 deletions(-) diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 22aae06e8..5b99ff675 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -235,6 +235,18 @@ static uint32_t _pollInput(void) { 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 @@ int main() { .params = { 320, 240, font, "/", - _drawStart, _drawEnd, _pollInput, + _drawStart, _drawEnd, + _pollInput, _pollCursor, 0, 0, GUI_PARAMS_TRAIL diff --git a/src/platform/psp2/CMakeLists.txt b/src/platform/psp2/CMakeLists.txt index 72295d5b6..d03f61182 100644 --- a/src/platform/psp2/CMakeLists.txt +++ b/src/platform/psp2/CMakeLists.txt @@ -5,7 +5,7 @@ source_group("PS Vita-specific code" FILES ${OS_SRC}) 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) diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 31393c037..0dd1ad8a8 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -63,15 +64,27 @@ static uint32_t _pollInput(void) { 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 }, diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index 8f37b6cf5..b4277c512 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -34,6 +34,7 @@ static int32_t _readGyroZ(struct GBARotationSource* source); 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 @@ int main() { .params = { 352, 230, font, "/", - _drawStart, _drawEnd, _pollInput, + _drawStart, _drawEnd, + _pollInput, _pollCursor, _guiPrepare, _guiFinish, GUI_PARAMS_TRAIL @@ -254,7 +257,7 @@ static uint32_t _pollInput(void) { ((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 @@ static uint32_t _pollInput(void) { 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 @@ void _gameUnloaded(struct GBAGUIRunner* runner) { } 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) { diff --git a/src/util/gui.c b/src/util/gui.c index 0d03fae4b..85c09a1c7 100644 --- a/src/util/gui.c +++ b/src/util/gui.c @@ -31,6 +31,37 @@ void GUIPollInput(struct GUIParams* params, uint32_t* newInputOut, uint32_t* hel } } +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; diff --git a/src/util/gui.h b/src/util/gui.h index 263e2c10c..621565152 100644 --- a/src/util/gui.h +++ b/src/util/gui.h @@ -28,6 +28,14 @@ enum GUIInput { 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 @@ struct GUIParams { 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 diff --git a/src/util/gui/menu.c b/src/util/gui/menu.c index 5469ed786..9481cbd70 100644 --- a/src/util/gui/menu.c +++ b/src/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; @@ -44,17 +48,28 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men 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 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men 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 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men 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 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men 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;