mirror of https://github.com/mgba-emu/mgba.git
GUI: Support for touch/cursor
This commit is contained in:
parent
2dcefe8fa5
commit
4cf016d442
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#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 @@ 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
|
||||
},
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue