diff --git a/src/gba/context/context.c b/src/gba/context/context.c index fe219cc88..18f70094c 100644 --- a/src/gba/context/context.c +++ b/src/gba/context/context.c @@ -56,8 +56,8 @@ bool GBAContextInit(struct GBAContext* context, const char* port) { .idleOptimization = IDLE_LOOP_DETECT, .logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL | GBA_LOG_STATUS }; - GBAConfigLoadDefaults(&context->config, &opts); GBAConfigLoad(&context->config); + GBAConfigLoadDefaults(&context->config, &opts); } context->gba->sync = 0; diff --git a/src/gba/gui/gui-config.c b/src/gba/gui/gui-config.c new file mode 100644 index 000000000..c3d6f5ad3 --- /dev/null +++ b/src/gba/gui/gui-config.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gui-config.h" + +#include "gba/gui/gui-runner.h" +#include "util/gui/file-select.h" +#include "util/gui/menu.h" + +void GBAGUIShowConfig(struct GBAGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra) { + struct GUIMenu menu = { + .title = "Configure", + .index = 0, + .background = &runner->background.d + }; + GUIMenuItemListInit(&menu.items, 0); + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Use BIOS if found", + .data = "useBios", + .submenu = 0, + .state = true, + .validStates = (const char*[]) { + "Off", "On", 0 + } + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Select BIOS path", + .data = "bios", + }; + size_t i; + for (i = 0; i < nExtra; ++i) { + *GUIMenuItemListAppend(&menu.items) = extra[i]; + } + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Save", + .data = "[SAVE]", + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Cancel", + .data = 0, + }; + enum GUIMenuExitReason reason; + char biosPath[256] = ""; + + struct GUIMenuItem* item; + for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { + item = GUIMenuItemListGetPointer(&menu.items, i); + if (!item->validStates || !item->data) { + continue; + } + GBAConfigGetUIntValue(&runner->context.config, item->data, &item->state); + } + + while (true) { + reason = GUIShowMenu(&runner->params, &menu, &item); + if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) { + break; + } + if (!strcmp(item->data, "[SAVE]")) { + if (biosPath[0]) { + GBAConfigSetValue(&runner->context.config, "bios", biosPath); + } + for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { + item = GUIMenuItemListGetPointer(&menu.items, i); + if (!item->validStates || !item->data) { + continue; + } + GBAConfigSetUIntValue(&runner->context.config, item->data, item->state); + } + GBAConfigSave(&runner->context.config); + break; + } + if (!strcmp(item->data, "bios")) { + // TODO: show box if failed + if (!GUISelectFile(&runner->params, biosPath, sizeof(biosPath), GBAIsBIOS)) { + biosPath[0] = '\0'; + } + continue; + } + if (item->validStates) { + ++item->state; + if (!item->validStates[item->state]) { + item->state = 0; + } + } + } +} diff --git a/src/gba/gui/gui-config.h b/src/gba/gui/gui-config.h new file mode 100644 index 000000000..2f38dbb1a --- /dev/null +++ b/src/gba/gui/gui-config.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_CONFIG_H +#define GUI_CONFIG_H + +#include "util/common.h" + +struct GBAGUIRunner; +struct GUIMenuItem; +void GBAGUIShowConfig(struct GBAGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra); + +#endif diff --git a/src/gba/gui/gui-runner.c b/src/gba/gui/gui-runner.c index b5256287c..57330d781 100644 --- a/src/gba/gui/gui-runner.c +++ b/src/gba/gui/gui-runner.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gui-runner.h" +#include "gba/gui/gui-config.h" #include "gba/interface.h" #include "gba/serialize.h" #include "util/gui/file-select.h" @@ -176,6 +177,7 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) }; #endif *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT }; while (true) { @@ -248,24 +250,24 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { } GUIInvalidateKeys(&runner->params); uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable! - struct GUIMenuItem item; + struct GUIMenuItem* item; enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item); if (reason == GUI_MENU_EXIT_ACCEPT) { struct VFile* vf; - switch (((int) item.data) & RUNNER_COMMAND_MASK) { + switch (((int) item->data) & RUNNER_COMMAND_MASK) { case RUNNER_EXIT: running = false; keys = 0; break; case RUNNER_SAVE_STATE: - vf = GBAGetState(runner->context.gba, 0, ((int) item.data) >> 16, true); + vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, true); if (vf) { GBASaveStateNamed(runner->context.gba, vf, true); vf->close(vf); } break; case RUNNER_LOAD_STATE: - vf = GBAGetState(runner->context.gba, 0, ((int) item.data) >> 16, false); + vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, false); if (vf) { GBALoadStateNamed(runner->context.gba, vf); vf->close(vf); @@ -274,6 +276,9 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { case RUNNER_SCREENSHOT: GBATakeScreenshot(runner->context.gba, 0); break; + case RUNNER_CONFIG: + GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); + break; case RUNNER_CONTINUE: break; } diff --git a/src/gba/gui/gui-runner.h b/src/gba/gui/gui-runner.h index 4fb739b72..0ca400940 100644 --- a/src/gba/gui/gui-runner.h +++ b/src/gba/gui/gui-runner.h @@ -35,6 +35,9 @@ struct GBAGUIRunner { struct GBAGUIBackground background; struct GBAGUIRunnerLux luminanceSource; + struct GUIMenuItem* configExtra; + size_t nConfigExtra; + void (*setup)(struct GBAGUIRunner*); void (*teardown)(struct GBAGUIRunner*); void (*gameLoaded)(struct GBAGUIRunner*); diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index bdeb30261..1b76515e1 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -11,6 +11,7 @@ #include "util/gui.h" #include "util/gui/file-select.h" #include "util/gui/font.h" +#include "util/gui/menu.h" #include "util/memory.h" #include "3ds-vfs.h" @@ -82,6 +83,11 @@ static void _setup(struct GBAGUIRunner* runner) { renderer.outputBufferStride = 256; runner->context.renderer = &renderer.d; + unsigned mode; + if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode < SM_MAX) { + screenMode = mode; + } + GBAAudioResizeBuffer(&runner->context.gba->audio, AUDIO_SAMPLES); } @@ -235,7 +241,13 @@ static void _incrementScreenMode(struct GBAGUIRunner* runner) { _drawEnd(); _drawStart(); _drawEnd(); - screenMode = (screenMode + 1) % SM_MAX; + unsigned mode; + if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode != screenMode) { + screenMode = mode; + } else { + screenMode = (screenMode + 1) % SM_MAX; + GBAConfigSetUIntValue(&runner->context.config, "screenMode", screenMode); + } } static uint32_t _pollInput(void) { @@ -395,6 +407,24 @@ int main() { GUI_PARAMS_TRAIL }, + .configExtra = (struct GUIMenuItem[]) { + { + .title = "Screen mode", + .data = "screenMode", + .submenu = 0, + .state = SM_PA_TOP, + .validStates = (const char*[]) { + "Pixel-Accurate/Bottom", + "Aspect-Ratio Fit/Bottom", + "Stretched/Bottom", + "Pixel-Accurate/Top", + "Aspect-Ratio Fit/Top", + "Stretched/Top", + 0 + } + } + }, + .nConfigExtra = 1, .setup = _setup, .teardown = 0, .gameLoaded = _gameLoaded, diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index d06aff0e6..67f386888 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -10,6 +10,7 @@ #include "util/gui.h" #include "util/gui/font.h" #include "util/gui/file-select.h" +#include "util/gui/menu.h" #include #include @@ -88,6 +89,21 @@ int main() { GUI_PARAMS_TRAIL }, + .configExtra = (struct GUIMenuItem[]) { + { + .title = "Screen mode", + .data = "screenMode", + .submenu = 0, + .state = 0, + .validStates = (const char*[]) { + "With Background", + "Without Background", + "Stretched", + 0 + } + } + }, + .nConfigExtra = 1, .setup = GBAPSP2Setup, .teardown = GBAPSP2Teardown, .gameLoaded = GBAPSP2LoadROM, diff --git a/src/platform/psp2/psp2-context.c b/src/platform/psp2/psp2-context.c index 548087c9a..6ad390f12 100644 --- a/src/platform/psp2/psp2-context.c +++ b/src/platform/psp2/psp2-context.c @@ -263,7 +263,13 @@ void GBAPSP2DrawScreenshot(struct GBAGUIRunner* runner, const uint32_t* pixels, } void GBAPSP2IncrementScreenMode(struct GBAGUIRunner* runner) { - screenMode = (screenMode + 1) % SM_MAX; + unsigned mode; + if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode != screenMode) { + screenMode = mode; + } else { + screenMode = (screenMode + 1) % SM_MAX; + GBAConfigSetUIntValue(&runner->context.config, "screenMode", screenMode); + } } __attribute__((noreturn, weak)) void __assert_func(const char* file, int line, const char* func, const char* expr) { diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c index 023fe4039..a8537a5b6 100644 --- a/src/util/gui/file-select.c +++ b/src/util/gui/file-select.c @@ -137,7 +137,7 @@ bool GUISelectFile(struct GUIParams* params, char* outPath, size_t outLen, bool _refreshDirectory(params, params->currentPath, &menu.items, filter); while (true) { - struct GUIMenuItem item; + struct GUIMenuItem* item; enum GUIMenuExitReason reason = GUIShowMenu(params, &menu, &item); params->fileIndex = menu.index; if (reason == GUI_MENU_EXIT_CANCEL) { @@ -155,7 +155,7 @@ bool GUISelectFile(struct GUIParams* params, char* outPath, size_t outLen, bool if (params->currentPath[len - 1] == *sep) { sep = ""; } - snprintf(outPath, outLen, "%s%s%s", params->currentPath, sep, item.title); + snprintf(outPath, outLen, "%s%s%s", params->currentPath, sep, item->title); struct GUIMenuItemList newFiles; GUIMenuItemListInit(&newFiles, 0); diff --git a/src/util/gui/menu.c b/src/util/gui/menu.c index ab9ad8846..9c0c536a9 100644 --- a/src/util/gui/menu.c +++ b/src/util/gui/menu.c @@ -10,7 +10,7 @@ DEFINE_VECTOR(GUIMenuItemList, struct GUIMenuItem); -enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem* item) { +enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem** item) { size_t start = 0; size_t lineHeight = GUIFontHeight(params->font); size_t pageSize = params->height / lineHeight; @@ -35,14 +35,24 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men ++menu->index; } if (newInput & (1 << GUI_INPUT_LEFT)) { - if (menu->index >= pageSize) { + struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu->items, menu->index); + if (item->validStates) { + if (item->state > 0) { + --item->state; + } + } else if (menu->index >= pageSize) { menu->index -= pageSize; } else { menu->index = 0; } } if (newInput & (1 << GUI_INPUT_RIGHT)) { - if (menu->index + pageSize < GUIMenuItemListSize(&menu->items)) { + struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu->items, menu->index); + if (item->validStates) { + if (item->validStates[item->state + 1]) { + ++item->state; + } + } else if (menu->index + pageSize < GUIMenuItemListSize(&menu->items)) { menu->index += pageSize; } else { menu->index = GUIMenuItemListSize(&menu->items) - 1; @@ -70,9 +80,9 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men break; } 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); + *item = GUIMenuItemListGetPointer(&menu->items, menu->index); + if ((*item)->submenu) { + enum GUIMenuExitReason reason = GUIShowMenu(params, (*item)->submenu, item); if (reason != GUI_MENU_EXIT_BACK) { return reason; } @@ -105,7 +115,11 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men color = 0xFFFFFFFF; bullet = '>'; } - GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, GUIMenuItemListGetPointer(&menu->items, i)->title); + struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu->items, i); + GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, item->title); + if (item->validStates) { + GUIFontPrintf(params->font, params->width, y, GUI_TEXT_RIGHT, color, "%s ", item->validStates[item->state]); + } y += lineHeight; if (y + lineHeight > params->height) { break; diff --git a/src/util/gui/menu.h b/src/util/gui/menu.h index 3ffb1c686..0ce52588a 100644 --- a/src/util/gui/menu.h +++ b/src/util/gui/menu.h @@ -12,6 +12,8 @@ struct GUIMenu; struct GUIMenuItem { const char* title; void* data; + unsigned state; + const char** validStates; struct GUIMenu* submenu; }; @@ -32,6 +34,6 @@ enum GUIMenuExitReason { }; struct GUIParams; -enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem* item); +enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem** item); #endif