mirror of
https://github.com/cavv-dev/Kekatsu-DS.git
synced 2025-06-18 16:55:40 -04:00
1836 lines
69 KiB
C
1836 lines
69 KiB
C
#include "menu.h"
|
|
|
|
#include "archives.h"
|
|
#include "brickColor1.h"
|
|
#include "brickColor2.h"
|
|
#include "colors.h"
|
|
#include "config.h"
|
|
#include "gettext.h"
|
|
#include "gui/box.h"
|
|
#include "gui/button.h"
|
|
#include "gui/image.h"
|
|
#include "gui/input.h"
|
|
#include "gui/keyboard.h"
|
|
#include "gui/progressbar.h"
|
|
#include "gui/screen.h"
|
|
#include "gui/text.h"
|
|
#include "gui/video.h"
|
|
#include "lButton.h"
|
|
#include "main.h"
|
|
#include "navbarBrowseIcon.h"
|
|
#include "navbarDatabasesIcon.h"
|
|
#include "navbarInfoIcon.h"
|
|
#include "navbarSettingsIcon.h"
|
|
#include "networking.h"
|
|
#include "rButton.h"
|
|
#include "settings.h"
|
|
#include "utils/filesystem.h"
|
|
#include "utils/math.h"
|
|
#include "utils/strings.h"
|
|
#include <nds.h>
|
|
#include <unistd.h>
|
|
|
|
// Current menu
|
|
MenuEnum menu;
|
|
|
|
// Choose color macro
|
|
#define col(x) colorSchemes[settings.colorScheme][x]
|
|
|
|
// Translate string macro
|
|
#define tr(x) gettext(x)
|
|
|
|
// Search parameters
|
|
char searchTitle[128];
|
|
size_t searchPage = 1;
|
|
|
|
Entry selectedEntry;
|
|
|
|
#define NAVBAR_BUTTONS_COUNT 4
|
|
|
|
struct Navbar {
|
|
GuiBox bg;
|
|
GuiBox btnBg;
|
|
GuiBox btnBgHover;
|
|
GuiImage btnIcons[NAVBAR_BUTTONS_COUNT];
|
|
GuiImage btnIconsHover[NAVBAR_BUTTONS_COUNT];
|
|
GuiButton btns[NAVBAR_BUTTONS_COUNT];
|
|
} navbar;
|
|
|
|
// Initializes the navbar with buttons and icons
|
|
void initNavbar(void)
|
|
{
|
|
navbar.bg = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_SECONDARY));
|
|
setGuiBoxPos(navbar.bg, 0, 160);
|
|
|
|
navbar.btnBg = newGuiBox(64, 32, col(COLOR_SECONDARY));
|
|
navbar.btnBgHover = newGuiBox(64, 32, col(COLOR_PRIMARY));
|
|
|
|
navbar.btnIcons[0] = newGuiImage(navbarBrowseIconBitmap, navbarBrowseIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIcons[1] = newGuiImage(navbarDatabasesIconBitmap, navbarDatabasesIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIcons[2] = newGuiImage(navbarSettingsIconBitmap, navbarSettingsIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIcons[3] = newGuiImage(navbarInfoIconBitmap, navbarInfoIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
|
|
navbar.btnIconsHover[0] = newGuiImage(navbarBrowseIconBitmap, navbarBrowseIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIconsHover[1] = newGuiImage(navbarDatabasesIconBitmap, navbarDatabasesIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIconsHover[2] = newGuiImage(navbarSettingsIconBitmap, navbarSettingsIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
navbar.btnIconsHover[3] = newGuiImage(navbarInfoIconBitmap, navbarInfoIconPal, 20, 20, 32, 32, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
|
|
for (size_t i = 0; i < NAVBAR_BUTTONS_COUNT; i++) {
|
|
setGuiImageColorTint(navbar.btnIcons[i], col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(navbar.btnIconsHover[i], col(COLOR_SECONDARY));
|
|
|
|
navbar.btns[i] = newGuiButton(64, 32);
|
|
setGuiButtonBg(navbar.btns[i], navbar.btnBg, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[i], navbar.btnIcons[i], navbar.btnIconsHover[i]);
|
|
setGuiButtonPos(navbar.btns[i], i * 64, 160);
|
|
}
|
|
}
|
|
|
|
// Frees the resources allocated for the navbar
|
|
void freeNavbar(void)
|
|
{
|
|
freeGuiBox(navbar.bg);
|
|
freeGuiBox(navbar.btnBgHover);
|
|
freeGuiImage(navbar.btnIcons[0]);
|
|
freeGuiImage(navbar.btnIcons[1]);
|
|
freeGuiImage(navbar.btnIcons[2]);
|
|
freeGuiImage(navbar.btnIcons[3]);
|
|
freeGuiImage(navbar.btnIconsHover[0]);
|
|
freeGuiImage(navbar.btnIconsHover[1]);
|
|
freeGuiImage(navbar.btnIconsHover[2]);
|
|
freeGuiImage(navbar.btnIconsHover[3]);
|
|
|
|
for (size_t i = 0; i < NAVBAR_BUTTONS_COUNT; i++)
|
|
freeGuiButton(navbar.btns[i]);
|
|
}
|
|
|
|
// Switches the current menu and updates the navbar buttons accordingly
|
|
void switchMenu(MenuEnum targetMenu)
|
|
{
|
|
// Set navbar buttons to original state
|
|
for (size_t i = 0; i < NAVBAR_BUTTONS_COUNT; i++) {
|
|
setGuiButtonBg(navbar.btns[i], navbar.btnBg, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[i], navbar.btnIcons[i], navbar.btnIconsHover[i]);
|
|
resetGuiButtonState(navbar.btns[i]);
|
|
}
|
|
|
|
switch (targetMenu) {
|
|
case MENU_BROWSE:
|
|
setGuiButtonBg(navbar.btns[0], navbar.btnBgHover, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[0], navbar.btnIconsHover[0], navbar.btnIconsHover[0]);
|
|
break;
|
|
case MENU_DATABASES:
|
|
setGuiButtonBg(navbar.btns[1], navbar.btnBgHover, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[1], navbar.btnIconsHover[1], navbar.btnIconsHover[1]);
|
|
break;
|
|
case MENU_SETTINGS:
|
|
setGuiButtonBg(navbar.btns[2], navbar.btnBgHover, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[2], navbar.btnIconsHover[2], navbar.btnIconsHover[2]);
|
|
break;
|
|
case MENU_INFO:
|
|
setGuiButtonBg(navbar.btns[3], navbar.btnBgHover, navbar.btnBgHover);
|
|
setGuiButtonIcon(navbar.btns[3], navbar.btnIconsHover[3], navbar.btnIconsHover[3]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
menu = targetMenu;
|
|
}
|
|
|
|
// Switches the menu based on which navbar button has been clicked
|
|
void navbarSwitchMenu(void)
|
|
{
|
|
for (size_t i = 0; i < NAVBAR_BUTTONS_COUNT; i++) {
|
|
if (getGuiButtonState(navbar.btns[i]) != GUI_BUTTON_STATE_CLICKED)
|
|
continue;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
switchMenu(MENU_BROWSE);
|
|
break;
|
|
case 1:
|
|
switchMenu(MENU_DATABASES);
|
|
break;
|
|
case 2:
|
|
switchMenu(MENU_SETTINGS);
|
|
break;
|
|
case 3:
|
|
switchMenu(MENU_INFO);
|
|
break;
|
|
}
|
|
|
|
resetGuiButtonState(navbar.btns[i]);
|
|
}
|
|
}
|
|
|
|
// Adds the navbar elements to the given screen
|
|
void addNavbarToGuiScreen(GuiScreen gs)
|
|
{
|
|
addToGuiScreen(gs, navbar.bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
for (size_t i = 0; i < NAVBAR_BUTTONS_COUNT; i++)
|
|
addToGuiScreen(gs, navbar.btns[i], GUI_ELEMENT_TYPE_BUTTON);
|
|
}
|
|
|
|
// Displays a keyboard interface to edit the given string
|
|
// Returns true if the changes to the string have been saved, false if ignored
|
|
bool keyboardEdit(char* str, size_t maxLength)
|
|
{
|
|
char tempStr[maxLength];
|
|
strncpy(tempStr, str, maxLength);
|
|
|
|
size_t pos = strlen(tempStr); // Char write position
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox topBg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
GuiBox bottomBg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG_2));
|
|
GuiBox buttonsBg = newGuiBox(SCREEN_WIDTH, 50, col(COLOR_SECONDARY));
|
|
setGuiBoxPos(buttonsBg, 0, 142);
|
|
|
|
GuiBox textboxBg = newGuiBox(224, 80, col(COLOR_BG_2));
|
|
setGuiBoxBorder(textboxBg, 2, col(COLOR_PRIMARY));
|
|
setGuiBoxPos(textboxBg, 16, 56);
|
|
|
|
GuiText textboxTxt = newGuiText(tempStr, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(textboxTxt, 128, 96);
|
|
setGuiTextAlignment(textboxTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(textboxTxt, 214);
|
|
setGuiTextMaxHeight(textboxTxt, 64);
|
|
setGuiTextWrap(textboxTxt, true);
|
|
|
|
GuiKeyboard keyboard = newGuiKeyboard(col(COLOR_TEXT_2), col(COLOR_PRIMARY));
|
|
setGuiKeyboardPos(keyboard, 0, 16);
|
|
|
|
GuiBox btnBg = newGuiBox(70, 28, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox btnBgHover = newGuiBox(70, 28, col(COLOR_PRIMARY));
|
|
|
|
GuiText btnTxt[2];
|
|
btnTxt[0] = newGuiText(tr("Ok"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
btnTxt[1] = newGuiText(tr("Cancel"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(btnTxt[0], GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextAlignment(btnTxt[1], GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiButton btn[2];
|
|
btn[0] = newGuiButton(70, 28);
|
|
btn[1] = newGuiButton(70, 28);
|
|
setGuiButtonBg(btn[0], btnBg, btnBgHover);
|
|
setGuiButtonBg(btn[1], btnBg, btnBgHover);
|
|
setGuiButtonLabel(btn[0], btnTxt[0]);
|
|
setGuiButtonLabel(btn[1], btnTxt[1]);
|
|
setGuiButtonPos(btn[0], 45, 152);
|
|
setGuiButtonPos(btn[1], 141, 152);
|
|
|
|
addToGuiScreen(topScreen, topBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, textboxBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, textboxTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addToGuiScreen(bottomScreen, bottomBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, keyboard, GUI_ELEMENT_TYPE_KEYBOARD);
|
|
addToGuiScreen(bottomScreen, buttonsBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, btn[0], GUI_ELEMENT_TYPE_BUTTON);
|
|
addToGuiScreen(bottomScreen, btn[1], GUI_ELEMENT_TYPE_BUTTON);
|
|
|
|
GuiScreen prevTopScreen = getActiveTopScreen();
|
|
GuiScreen prevBottomScreen = getActiveBottomScreen();
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
|
|
bool save = false;
|
|
while (pmMainLoop()) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
struct GuiKeyboardKey key = getGuiKeyboardPressed(keyboard);
|
|
|
|
if (key.c && pos + 1 <= maxLength) {
|
|
tempStr[pos] = key.c;
|
|
tempStr[++pos] = '\0';
|
|
setGuiTextText(textboxTxt, tempStr);
|
|
} else if (key.extraKey == GUI_KEYBOARD_EXTRA_KEY_BACKSPACE) {
|
|
if (pos > 0)
|
|
tempStr[--pos] = '\0';
|
|
setGuiTextText(textboxTxt, tempStr);
|
|
}
|
|
|
|
if (getGuiButtonState(btn[0]) == GUI_BUTTON_STATE_CLICKED) {
|
|
save = true;
|
|
strncpy(str, tempStr, maxLength - 1);
|
|
break;
|
|
} else if (getGuiButtonState(btn[1]) == GUI_BUTTON_STATE_CLICKED) {
|
|
save = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(topBg);
|
|
freeGuiBox(bottomBg);
|
|
freeGuiBox(buttonsBg);
|
|
freeGuiBox(textboxBg);
|
|
freeGuiText(textboxTxt);
|
|
freeGuiKeyboard(keyboard);
|
|
freeGuiBox(btnBg);
|
|
freeGuiBox(btnBgHover);
|
|
freeGuiText(btnTxt[0]);
|
|
freeGuiText(btnTxt[1]);
|
|
freeGuiButton(btn[0]);
|
|
freeGuiButton(btn[1]);
|
|
|
|
setActiveScreens(prevTopScreen, prevBottomScreen);
|
|
|
|
return save;
|
|
}
|
|
|
|
// Displays a prompt window with the given title and message
|
|
// Returns true if the first option is clicked, false if the second option is clicked
|
|
bool windowPrompt(const char* title, const char* message, const char* btn1Label, const char* btn2Label)
|
|
{
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiBox promptBg = newGuiBox(244, 132, col(COLOR_BG_2));
|
|
setGuiBoxBorder(promptBg, 2, col(COLOR_PRIMARY));
|
|
setGuiBoxPos(promptBg, 6, 6);
|
|
|
|
GuiText titleTxt = newGuiText(title, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(titleTxt, 128, 25);
|
|
setGuiTextAlignment(titleTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText messageTxt = newGuiText(message, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(messageTxt, 128, 78);
|
|
setGuiTextAlignment(messageTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(messageTxt, 224);
|
|
setGuiTextMaxHeight(messageTxt, 100);
|
|
setGuiTextWrap(messageTxt, true);
|
|
|
|
GuiText btn1Txt = NULL;
|
|
GuiText btn2Txt = NULL;
|
|
GuiBox btnBg1 = NULL;
|
|
GuiBox btnBg1Hover = NULL;
|
|
GuiBox btnBg2 = NULL;
|
|
GuiBox btnBg2Hover = NULL;
|
|
GuiButton btn1 = NULL;
|
|
GuiButton btn2 = NULL;
|
|
|
|
btn1Txt = newGuiText(btn1Label, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(btn1Txt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
size_t btn1Width = max(70, getGuiTextWidth(btn1Txt) + 20);
|
|
|
|
btnBg1 = newGuiBox(btn1Width, 28, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg1, 2, col(COLOR_PRIMARY));
|
|
btnBg1Hover = newGuiBox(btn1Width, 28, col(COLOR_PRIMARY));
|
|
|
|
btn1 = newGuiButton(btn1Width, 28);
|
|
setGuiButtonBg(btn1, btnBg1, btnBg1Hover);
|
|
setGuiButtonLabel(btn1, btn1Txt);
|
|
setGuiButtonPos(btn1, 93, 152);
|
|
|
|
if (btn2Label) {
|
|
btn2Txt = newGuiText(btn2Label, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(btn2Txt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
size_t btn2Width = max(70, getGuiTextWidth(btn2Txt) + 20);
|
|
|
|
btnBg2 = newGuiBox(btn2Width, 28, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg2, 2, col(COLOR_PRIMARY));
|
|
btnBg2Hover = newGuiBox(btn2Width, 28, col(COLOR_PRIMARY));
|
|
|
|
btn2 = newGuiButton(btn2Width, 28);
|
|
setGuiButtonBg(btn2, btnBg2, btnBg2Hover);
|
|
setGuiButtonLabel(btn2, btn2Txt);
|
|
|
|
setGuiButtonPos(btn1, 80 - btn1Width / 2, 152);
|
|
setGuiButtonPos(btn2, 176 - btn2Width / 2, 152);
|
|
}
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, promptBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, titleTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, messageTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, btn1, GUI_ELEMENT_TYPE_BUTTON);
|
|
if (btn2Label)
|
|
addToGuiScreen(bottomScreen, btn2, GUI_ELEMENT_TYPE_BUTTON);
|
|
|
|
GuiScreen prevTopScreen = getActiveTopScreen();
|
|
GuiScreen prevBottomScreen = getActiveBottomScreen();
|
|
|
|
setActiveScreens(NULL, bottomScreen);
|
|
|
|
bool ret = true;
|
|
while (pmMainLoop()) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(btn1) == GUI_BUTTON_STATE_CLICKED)
|
|
break;
|
|
|
|
if (btn2Label && getGuiButtonState(btn2) == GUI_BUTTON_STATE_CLICKED) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiBox(promptBg);
|
|
freeGuiText(titleTxt);
|
|
freeGuiText(messageTxt);
|
|
freeGuiText(btn1Txt);
|
|
freeGuiBox(btnBg1);
|
|
freeGuiBox(btnBg1Hover);
|
|
freeGuiButton(btn1);
|
|
|
|
if (btn2Label) {
|
|
freeGuiText(btn2Txt);
|
|
freeGuiBox(btnBg2);
|
|
freeGuiBox(btnBg2Hover);
|
|
freeGuiButton(btn2);
|
|
}
|
|
|
|
setActiveScreens(prevTopScreen, prevBottomScreen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Displays a message on the bottom screen in a non-blocking way
|
|
void showMessage(const char* message)
|
|
{
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiText messageTxt = newGuiText(message, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(messageTxt, 128, 96);
|
|
setGuiTextAlignment(messageTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(messageTxt, 244);
|
|
setGuiTextWrap(messageTxt, true);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, messageTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
GuiScreen prevTopScreen = getActiveTopScreen();
|
|
GuiScreen prevBottomScreen = getActiveBottomScreen();
|
|
|
|
setActiveScreens(NULL, bottomScreen);
|
|
|
|
// Make sure to draw bottom screen
|
|
guiLoop();
|
|
drawScreens();
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiText(messageTxt);
|
|
|
|
setActiveScreens(prevTopScreen, prevBottomScreen);
|
|
}
|
|
|
|
// Draws a black background on both screens
|
|
void drawBlank(void)
|
|
{
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, 0);
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
|
|
// Make sure to draw both screens
|
|
guiLoop();
|
|
drawScreens();
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
}
|
|
|
|
// Downloads and loads a box art file of a given entry into a new GuiImage element
|
|
// Returns the created GuiImage element
|
|
GuiImage loadBoxart(Entry e)
|
|
{
|
|
char boxartFilename[NAME_MAX];
|
|
strncpy(boxartFilename, getEntryBoxartUrl(e), sizeof(boxartFilename) - 1);
|
|
safeStr(boxartFilename);
|
|
|
|
char boxartPath[PATH_MAX];
|
|
joinPath(boxartPath, CACHE_DIR, boxartFilename);
|
|
|
|
if (!fileExists(boxartPath))
|
|
downloadFile(boxartPath, getEntryBoxartUrl(e), NULL);
|
|
|
|
return newGuiImagePNG(boxartPath, 144, 144);
|
|
}
|
|
|
|
// Data and elements used dynamically by the downloadProgressCallback function
|
|
struct DlData {
|
|
GuiText fileNameTxt;
|
|
GuiProgressbar progressBar;
|
|
GuiText percentTxt;
|
|
GuiText speedTxt;
|
|
GuiText progressTxt;
|
|
GuiButton cancelBtn;
|
|
time_t lastSpeedUpdateTime;
|
|
size_t lastDlnow;
|
|
} dlData;
|
|
|
|
// curl download progress function
|
|
// Draws the download progress interface
|
|
size_t downloadProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
|
{
|
|
guiLoop();
|
|
|
|
char humanSizeDlnow[16];
|
|
char humanSizeDltotal[16];
|
|
|
|
humanizeSize(humanSizeDlnow, sizeof(humanSizeDlnow), dlnow);
|
|
humanizeSize(humanSizeDltotal, sizeof(humanSizeDltotal), dltotal);
|
|
|
|
char progressText[64];
|
|
char percentText[16];
|
|
|
|
sprintf(progressText, "%s / %s", humanSizeDlnow, humanSizeDltotal);
|
|
|
|
size_t percent = 0;
|
|
if (dltotal) {
|
|
percent = (double)dlnow / dltotal * 100;
|
|
sprintf(percentText, "%d %%", percent);
|
|
} else {
|
|
percentText[0] = '\0';
|
|
}
|
|
|
|
setGuiProgressbarPercent(dlData.progressBar, percent);
|
|
setGuiTextText(dlData.percentTxt, percentText);
|
|
setGuiTextText(dlData.progressTxt, progressText);
|
|
|
|
time_t currentTime = time(NULL);
|
|
|
|
// Update speed if 1 second elapsed
|
|
if ((currentTime - dlData.lastSpeedUpdateTime >= 1)) {
|
|
char humanSizeSpeed[16];
|
|
humanizeSize(humanSizeSpeed, sizeof(humanSizeSpeed), dlnow - dlData.lastDlnow);
|
|
|
|
char speedText[32];
|
|
snprintf(speedText, sizeof(speedText), "%s/s", humanSizeSpeed);
|
|
|
|
setGuiTextText(dlData.speedTxt, speedText);
|
|
dlData.lastSpeedUpdateTime = currentTime;
|
|
dlData.lastDlnow = dlnow;
|
|
}
|
|
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(dlData.cancelBtn) == GUI_BUTTON_STATE_CLICKED) {
|
|
resetGuiButtonState(dlData.cancelBtn);
|
|
stopDownload();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Sets up the download progress interface and starts the download
|
|
// Returns the download status
|
|
DownloadStatus downloadGui(const char* path, const char* url, const char* fileName)
|
|
{
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
dlData.fileNameTxt = newGuiText(fileName, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(dlData.fileNameTxt, 14, 56);
|
|
setGuiTextAlignment(dlData.fileNameTxt, GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_BOTTOM);
|
|
setGuiTextMaxWidth(dlData.fileNameTxt, 216);
|
|
setGuiTextWrap(dlData.fileNameTxt, true);
|
|
setGuiTextMaxHeight(dlData.fileNameTxt, 60);
|
|
|
|
GuiBox progressBarBg = newGuiBox(228, 26, col(COLOR_BG_2));
|
|
setGuiBoxBorder(progressBarBg, 2, col(COLOR_PRIMARY));
|
|
setGuiBoxPos(progressBarBg, 12, 60);
|
|
dlData.progressBar = newGuiProgressbar(224, 22, col(COLOR_BG_2), col(COLOR_PRIMARY));
|
|
setGuiProgressbarPos(dlData.progressBar, 14, 62);
|
|
|
|
dlData.percentTxt = newGuiText("", GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(dlData.percentTxt, 128, 73);
|
|
setGuiTextAlignment(dlData.percentTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
dlData.speedTxt = newGuiText("", GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(dlData.speedTxt, 14, 92);
|
|
|
|
dlData.progressTxt = newGuiText("", GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(dlData.progressTxt, 242, 92);
|
|
setGuiTextAlignment(dlData.progressTxt, GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_TOP);
|
|
|
|
GuiBox cancelBtnBg = newGuiBox(90, 34, col(COLOR_BG_2));
|
|
setGuiBoxBorder(cancelBtnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox cancelBtnBgHover = newGuiBox(90, 34, col(COLOR_PRIMARY));
|
|
GuiText cancelBtnTxt = newGuiText(tr("Cancel"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(cancelBtnTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
dlData.cancelBtn = newGuiButton(90, 34);
|
|
setGuiButtonPos(dlData.cancelBtn, 83, 124);
|
|
setGuiButtonBg(dlData.cancelBtn, cancelBtnBg, cancelBtnBgHover);
|
|
setGuiButtonLabel(dlData.cancelBtn, cancelBtnTxt);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, dlData.fileNameTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, progressBarBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, dlData.progressBar, GUI_ELEMENT_TYPE_PROGRESSBAR);
|
|
addToGuiScreen(bottomScreen, dlData.percentTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, dlData.speedTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, dlData.progressTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, dlData.cancelBtn, GUI_ELEMENT_TYPE_BUTTON);
|
|
|
|
setActiveScreens(NULL, bottomScreen);
|
|
|
|
dlData.lastSpeedUpdateTime = 0;
|
|
dlData.lastDlnow = 0;
|
|
DownloadStatus dlStatus = downloadFile(path, url, downloadProgressCallback);
|
|
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiText(dlData.fileNameTxt);
|
|
freeGuiBox(progressBarBg);
|
|
freeGuiProgressbar(dlData.progressBar);
|
|
freeGuiText(dlData.percentTxt);
|
|
freeGuiText(dlData.speedTxt);
|
|
freeGuiText(dlData.progressTxt);
|
|
freeGuiBox(cancelBtnBg);
|
|
freeGuiBox(cancelBtnBgHover);
|
|
freeGuiText(cancelBtnTxt);
|
|
freeGuiButton(dlData.cancelBtn);
|
|
|
|
return dlStatus;
|
|
}
|
|
|
|
// Handles the download of the given entry
|
|
void downloadEntry(Entry e)
|
|
{
|
|
char downloadDirPath[PATH_MAX];
|
|
char downloadFilePath[PATH_MAX];
|
|
char tempMessage[128];
|
|
|
|
if (settings.dlUseDirs)
|
|
joinPath(downloadDirPath, settings.dlPath, getEntryPlatform(e));
|
|
else
|
|
strcpy(downloadDirPath, settings.dlPath);
|
|
|
|
joinPath(downloadFilePath, downloadDirPath, getEntryFileName(e));
|
|
|
|
if (!createDir(downloadDirPath)) {
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Download failed"), tr("could not create download directory"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
}
|
|
|
|
DownloadStatus dlStatus = downloadGui(downloadFilePath, getEntryUrl(e), getEntryFileName(e));
|
|
|
|
switch (dlStatus) {
|
|
case DOWNLOAD_STOPPED:
|
|
return;
|
|
case DOWNLOAD_ERR_NOT_OK:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Download failed"), tr("bad response status"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
case DOWNLOAD_ERR_INIT_FAILED:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Download failed"), tr("could not initialize download"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
case DOWNLOAD_ERR_FILE_OPEN_FAILED:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Download failed"), tr("could not create file"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
case DOWNLOAD_ERR_PERFORM_FAILED:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Download failed"), tr("could not perform download"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!fileIsZip(downloadFilePath)) {
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s\n(%s)", tr("Download completed"), getEntryTitle(e));
|
|
windowPrompt(tr("Info"), tempMessage, tr("Ok"), NULL);
|
|
return;
|
|
}
|
|
|
|
ExtractStatus extractStatus;
|
|
char tempExtractPath[PATH_MAX];
|
|
|
|
size_t extractItemsCount = getEntryExtractItemsCount(e);
|
|
if (extractItemsCount) {
|
|
struct EntryExtractItem* extractItems = getEntryExtractItems(e);
|
|
for (size_t i = 0; i < extractItemsCount; i++) {
|
|
joinPath(tempExtractPath, downloadDirPath, extractItems[i].outPath);
|
|
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s (%s)", tr("Extracting content..."), extractItems[i].inPath);
|
|
showMessage(tempMessage);
|
|
|
|
extractStatus = extractZip(downloadFilePath, extractItems[i].inPath, tempExtractPath);
|
|
|
|
switch (extractStatus) {
|
|
case EXTRACT_ERR_FILE_OPEN:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s (%s)", tr("Extraction failed"), tr("could not open file"), extractItems[i].inPath);
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
case EXTRACT_ERR_FILE_NOT_FOUND:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s (%s)", tr("Extraction failed"), tr("could not locate file"), extractItems[i].inPath);
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
case EXTRACT_ERR_FILE_READ:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s (%s)", tr("Extraction failed"), tr("could not read file"), extractItems[i].inPath);
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
case EXTRACT_ERR_FILE_WRITE:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s (%s)", tr("Extraction failed"), tr("could not write file"), extractItems[i].inPath);
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (extractStatus != EXTRACT_SUCCESS) {
|
|
for (size_t j = 0; j < extractItemsCount; j++)
|
|
deletePath(extractItems[j].outPath);
|
|
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
char* tempDirName = strdup(getEntryTitle(e));
|
|
safeStr(tempDirName);
|
|
|
|
joinPath(tempExtractPath, downloadDirPath, tempDirName);
|
|
|
|
free(tempDirName);
|
|
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s (%.124s)", tr("Do you wish to extract the content in a separate directory?"), tempExtractPath);
|
|
|
|
if (!windowPrompt(tr("Prompt"), tempMessage, tr("Yes"), tr("No")))
|
|
strcpy(tempExtractPath, downloadDirPath);
|
|
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s (%.124s)", tr("Extracting content..."), tempExtractPath);
|
|
showMessage(tempMessage);
|
|
|
|
extractStatus = extractAllZip(downloadFilePath, tempExtractPath);
|
|
|
|
switch (extractStatus) {
|
|
case EXTRACT_ERR_FILE_OPEN:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Extraction failed"), tr("could not open file"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
case EXTRACT_ERR_FILE_READ:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Extraction failed"), tr("could not read file"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
case EXTRACT_ERR_FILE_WRITE:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Extraction failed"), tr("could not write file"));
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (extractStatus == EXTRACT_SUCCESS) {
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s\n(%s)", tr("Download completed"), getEntryTitle(e));
|
|
windowPrompt(tr("Info"), tempMessage, tr("Ok"), NULL);
|
|
}
|
|
|
|
deleteFile(downloadFilePath);
|
|
}
|
|
|
|
#define UPDATE_TEMP_FILENAME "tmpUpdateFile"
|
|
#define UPDATE_FILENAME "Kekatsu.nds"
|
|
|
|
// Handles the download of the update file
|
|
void downloadUpdate(void)
|
|
{
|
|
char workDir[PATH_MAX];
|
|
getcwd(workDir, sizeof(workDir));
|
|
|
|
char downloadFilePath[PATH_MAX];
|
|
joinPath(downloadFilePath, workDir, UPDATE_TEMP_FILENAME);
|
|
|
|
DownloadStatus dlStatus = downloadGui(downloadFilePath, UPDATE_URL_APP, UPDATE_FILENAME);
|
|
|
|
if (dlStatus != DOWNLOAD_SUCCESS) {
|
|
if (dlStatus != DOWNLOAD_STOPPED)
|
|
windowPrompt(tr("Error"), tr("Could not download update"), tr("Ok"), NULL);
|
|
return;
|
|
}
|
|
|
|
char execPath[PATH_MAX];
|
|
joinPath(execPath, workDir, UPDATE_FILENAME);
|
|
|
|
renamePath(downloadFilePath, execPath);
|
|
|
|
if (windowPrompt(tr("Info"), tr("Update downloaded successfully. Do you want to reboot now?"), tr("Yes"), tr("No")))
|
|
switchMenu(MENU_EXIT);
|
|
}
|
|
|
|
// Handles the update check and download
|
|
void handleUpdateCheck(void)
|
|
{
|
|
showMessage(tr("Checking for updates..."));
|
|
|
|
char newVersion[16];
|
|
DownloadStatus dlStatus = downloadToString(newVersion, sizeof(newVersion), UPDATE_URL_VERSION);
|
|
|
|
if (dlStatus != DOWNLOAD_SUCCESS)
|
|
return;
|
|
|
|
newVersion[strcspn(newVersion, "\r\n")] = '\0';
|
|
|
|
if (strcmp(APP_VERSION, newVersion) == 0)
|
|
return;
|
|
|
|
char tempMessage[128];
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("New version found"), newVersion);
|
|
|
|
if (!windowPrompt(tr("Info"), tempMessage, tr("Update"), tr("Ignore")))
|
|
return;
|
|
|
|
downloadUpdate();
|
|
}
|
|
|
|
// Handles the loading of the given database
|
|
// Returns true if the database has been loaded, false if there was an error
|
|
bool loadDatabase(Database d)
|
|
{
|
|
char tempMessage[128];
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s (%s)", tr("Loading database..."), getDatabaseName(d));
|
|
showMessage(tempMessage);
|
|
|
|
DatabaseInitStatus initStatus = initDatabase(d);
|
|
switch (initStatus) {
|
|
case DATABASE_INIT_ERR_DOWNLOAD:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Failed to initialize database"), tr("download failed"));
|
|
break;
|
|
case DATABASE_INIT_ERR_FILE_NOT_FOUND:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Failed to initialize database"), tr("file not found"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (initStatus != DATABASE_INIT_SUCCESS && initStatus != DATABASE_INIT_SUCCESS_CACHE) {
|
|
windowPrompt(tr("Error"), tempMessage, tr("Ok"), NULL);
|
|
return false;
|
|
}
|
|
|
|
DatabaseOpenStatus openStatus = openDatabase(d);
|
|
switch (openStatus) {
|
|
case DATABASE_OPEN_ERR_FILE_OPEN:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Database open failed"), tr("could not open file"));
|
|
break;
|
|
case DATABASE_OPEN_ERR_INVALID_VERSION:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Database open failed"), tr("invalid version"));
|
|
break;
|
|
case DATABASE_OPEN_ERR_INVALID_FORMAT:
|
|
snprintf(tempMessage, sizeof(tempMessage), "%s: %s", tr("Database open failed"), tr("invalid format"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (openStatus != DATABASE_OPEN_SUCCESS) {
|
|
windowPrompt(tr("Error"), tempMessage, "OK", NULL);
|
|
return false;
|
|
}
|
|
|
|
if (db)
|
|
freeDatabase(db);
|
|
db = d;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Loads the last opened database
|
|
void loadLastOpenedDb(void)
|
|
{
|
|
Database lastDb = getLastOpenedDatabase();
|
|
if (!lastDb)
|
|
return;
|
|
|
|
if (!loadDatabase(lastDb))
|
|
freeDatabase(lastDb);
|
|
}
|
|
|
|
// Browse menu
|
|
// Displays the search options
|
|
void browseMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
char menuTitleText[32];
|
|
snprintf(menuTitleText, sizeof(menuTitleText), "%s (%d)", tr("Browse"), (db ? getDatabaseSize(db) : 0));
|
|
|
|
GuiText menuTitle = newGuiText(menuTitleText, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(menuTitle, 128, 178);
|
|
setGuiTextAlignment(menuTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiBox btnBg = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox btnBgHover = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_PRIMARY));
|
|
|
|
GuiText btn1Txt = newGuiText(tr("Search by title"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(btn1Txt, 12, 0);
|
|
setGuiTextAlignment(btn1Txt, GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
GuiButton btn1 = newGuiButton(SCREEN_WIDTH, 32);
|
|
setGuiButtonBg(btn1, btnBg, btnBgHover);
|
|
setGuiButtonLabel(btn1, btn1Txt);
|
|
|
|
GuiText btn2Txt = newGuiText(tr("Browse all"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(btn2Txt, 12, 0);
|
|
setGuiTextAlignment(btn2Txt, GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
GuiButton btn2 = newGuiButton(SCREEN_WIDTH, 32);
|
|
setGuiButtonBg(btn2, btnBg, btnBgHover);
|
|
setGuiButtonLabel(btn2, btn2Txt);
|
|
setGuiButtonPos(btn2, 0, 32);
|
|
|
|
GuiText noDatabaseTxt = newGuiText(tr("No database loaded or initialized"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_3));
|
|
setGuiTextPos(noDatabaseTxt, 128, 80);
|
|
setGuiTextAlignment(noDatabaseTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(noDatabaseTxt, 244);
|
|
setGuiTextWrap(noDatabaseTxt, true);
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, menuTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
if (db && getDatabaseIsInited(db)) {
|
|
addToGuiScreen(bottomScreen, btn1, GUI_ELEMENT_TYPE_BUTTON);
|
|
addToGuiScreen(bottomScreen, btn2, GUI_ELEMENT_TYPE_BUTTON);
|
|
} else {
|
|
addToGuiScreen(bottomScreen, noDatabaseTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
}
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(btn1) == GUI_BUTTON_STATE_CLICKED) {
|
|
if (keyboardEdit(searchTitle, sizeof(searchTitle))) {
|
|
searchPage = 1;
|
|
switchMenu(MENU_RESULTS);
|
|
}
|
|
resetGuiButtonState(btn1);
|
|
} else if (getGuiButtonState(btn2) == GUI_BUTTON_STATE_CLICKED) {
|
|
searchTitle[0] = '\0';
|
|
searchPage = 1;
|
|
switchMenu(MENU_RESULTS);
|
|
}
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
freeGuiText(menuTitle);
|
|
freeGuiBox(btnBg);
|
|
freeGuiBox(btnBgHover);
|
|
freeGuiText(btn1Txt);
|
|
freeGuiButton(btn1);
|
|
freeGuiText(btn2Txt);
|
|
freeGuiButton(btn2);
|
|
freeGuiText(noDatabaseTxt);
|
|
}
|
|
|
|
#define MAX_RESULTS_PER_PAGE 50
|
|
#define MAX_RESULTS_DISPLAY 5
|
|
|
|
// Results menu
|
|
// Starts the search in the database with the set parameters and shows the results
|
|
void resultsMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
size_t resultsCount;
|
|
Entry* results = searchDatabase(db, searchTitle, MAX_RESULTS_PER_PAGE, searchPage, &resultsCount);
|
|
|
|
bool prevPageEnabled = (searchPage > 1);
|
|
bool nextPageEnabled = (resultsCount == MAX_RESULTS_PER_PAGE);
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
setGuiScreenDpadNavigate(topScreen, 0);
|
|
setGuiScreenDpadNavigate(bottomScreen, 0);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
char menuTitleText[16];
|
|
snprintf(menuTitleText, sizeof(menuTitleText), "%s %d (%d)", tr("Page"), searchPage, resultsCount);
|
|
GuiText menuTitle = newGuiText(menuTitleText, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(menuTitle, 128, 178);
|
|
setGuiTextAlignment(menuTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText prevPageTxt = newGuiText(tr("Previous"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
GuiText nextPageTxt = newGuiText(tr("Next"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
setGuiTextPos(prevPageTxt, 26, 180);
|
|
setGuiTextPos(nextPageTxt, 230, 180);
|
|
setGuiTextAlignment(prevPageTxt, GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextAlignment(nextPageTxt, GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiImage lButtonIcon = newGuiImage(lButtonBitmap, lButtonPal, 16, 10, 16, 16, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage rButtonIcon = newGuiImage(rButtonBitmap, rButtonPal, 16, 10, 16, 16, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImagePos(lButtonIcon, 6, 174);
|
|
setGuiImagePos(rButtonIcon, 234, 174);
|
|
|
|
GuiBox resultsBtnBg = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_BG_2));
|
|
setGuiBoxBorder(resultsBtnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox resultsBtnBgHover = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_PRIMARY));
|
|
|
|
GuiText resultsBtnTxt[resultsCount];
|
|
GuiText resultsBtnTxtPlatform[resultsCount];
|
|
GuiText resultsBtnTxtRegion[resultsCount];
|
|
GuiButton resultsBtn[resultsCount];
|
|
|
|
for (size_t i = 0; i < resultsCount; i++) {
|
|
resultsBtnTxt[i] = newGuiText(getEntryTitle(results[i]), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(resultsBtnTxt[i], 12, 0);
|
|
setGuiTextAlignment(resultsBtnTxt[i], GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(resultsBtnTxt[i], 186);
|
|
setGuiTextMaxHeight(resultsBtnTxt[i], 32);
|
|
setGuiTextWrap(resultsBtnTxt[i], true);
|
|
|
|
resultsBtnTxtPlatform[i] = newGuiText(getEntryPlatform(results[i]), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(resultsBtnTxtPlatform[i], GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(resultsBtnTxtPlatform[i], 48);
|
|
|
|
resultsBtnTxtRegion[i] = newGuiText(getEntryRegion(results[i]), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(resultsBtnTxtRegion[i], GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(resultsBtnTxtRegion[i], 48);
|
|
|
|
resultsBtn[i] = newGuiButton(SCREEN_WIDTH, 32);
|
|
setGuiButtonBg(resultsBtn[i], resultsBtnBg, resultsBtnBgHover);
|
|
setGuiButtonLabel(resultsBtn[i], resultsBtnTxt[i]);
|
|
}
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, menuTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
if (prevPageEnabled) {
|
|
addToGuiScreen(topScreen, prevPageTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(topScreen, lButtonIcon, GUI_ELEMENT_TYPE_IMAGE);
|
|
}
|
|
|
|
if (nextPageEnabled) {
|
|
addToGuiScreen(topScreen, nextPageTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(topScreen, rButtonIcon, GUI_ELEMENT_TYPE_IMAGE);
|
|
}
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
bool firstRun = true;
|
|
|
|
size_t scrollOffset = 0;
|
|
size_t selectOffset = 0;
|
|
|
|
bool selectUpAction = false;
|
|
bool selectDownAction = false;
|
|
bool scrollUpAction = false;
|
|
bool scrollDownAction = false;
|
|
bool scrollUpFastAction = false;
|
|
bool scrollDownFastAction = false;
|
|
|
|
bool clickAction = false;
|
|
|
|
bool nextPageAction = false;
|
|
bool prevPageAction = false;
|
|
|
|
bool selectAction = false;
|
|
bool scrollAction = false;
|
|
bool switchPageAction = false;
|
|
|
|
size_t displayedResultsCount = min(MAX_RESULTS_DISPLAY, resultsCount);
|
|
if (resultsCount > 0)
|
|
setGuiButtonState(resultsBtn[0], GUI_BUTTON_STATE_SELECTED);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
|
|
if (resultsCount > 0) {
|
|
selectUpAction = (pressed & KEY_UP);
|
|
selectDownAction = (pressed & KEY_DOWN);
|
|
scrollUpAction = (selectUpAction && getGuiButtonState(resultsBtn[scrollOffset]) == GUI_BUTTON_STATE_SELECTED); // Up is pressed and highest result is selected
|
|
scrollDownAction = (selectDownAction && getGuiButtonState(resultsBtn[scrollOffset + displayedResultsCount - 1]) == GUI_BUTTON_STATE_SELECTED); // Down is pressed and lowest result is selected
|
|
scrollUpFastAction = (pressed & KEY_LEFT);
|
|
scrollDownFastAction = (pressed & KEY_RIGHT);
|
|
clickAction = (pressed & KEY_A);
|
|
nextPageAction = (pressed & KEY_R);
|
|
prevPageAction = (pressed & KEY_L);
|
|
|
|
selectAction = selectUpAction || selectDownAction;
|
|
scrollAction = scrollUpAction || scrollDownAction || scrollUpFastAction || scrollDownFastAction;
|
|
switchPageAction = nextPageAction || prevPageAction;
|
|
|
|
if (scrollAction || firstRun) {
|
|
resetGuiButtonState(resultsBtn[scrollOffset + selectOffset]);
|
|
|
|
if (!firstRun) {
|
|
// Remove all displayed results
|
|
for (size_t i = 0; i < displayedResultsCount; i++) {
|
|
removeFromGuiScreen(bottomScreen, resultsBtn[i + scrollOffset]);
|
|
removeFromGuiScreen(bottomScreen, resultsBtnTxtPlatform[i + scrollOffset]);
|
|
removeFromGuiScreen(bottomScreen, resultsBtnTxtRegion[i + scrollOffset]);
|
|
}
|
|
} else {
|
|
firstRun = false;
|
|
}
|
|
|
|
if (scrollUpAction) {
|
|
if (scrollOffset > 0)
|
|
scrollOffset--;
|
|
|
|
setGuiButtonState(resultsBtn[scrollOffset], GUI_BUTTON_STATE_SELECTED);
|
|
selectOffset = 0;
|
|
} else if (scrollDownAction) {
|
|
if (scrollOffset < resultsCount - 5)
|
|
scrollOffset++;
|
|
|
|
setGuiButtonState(resultsBtn[scrollOffset + displayedResultsCount - 1], GUI_BUTTON_STATE_SELECTED);
|
|
selectOffset = displayedResultsCount - 1;
|
|
} else if (scrollUpFastAction) {
|
|
scrollOffset -= min(MAX_RESULTS_DISPLAY, scrollOffset);
|
|
|
|
setGuiButtonState(resultsBtn[scrollOffset], GUI_BUTTON_STATE_SELECTED);
|
|
selectOffset = 0;
|
|
} else if (scrollDownFastAction) {
|
|
size_t maxPossibleStep = resultsCount - displayedResultsCount - scrollOffset;
|
|
if (maxPossibleStep > 0)
|
|
scrollOffset += min(MAX_RESULTS_DISPLAY, maxPossibleStep);
|
|
|
|
setGuiButtonState(resultsBtn[scrollOffset], GUI_BUTTON_STATE_SELECTED);
|
|
selectOffset = 0;
|
|
}
|
|
|
|
// Add displayed results according to scroll offset
|
|
for (size_t i = 0; i < displayedResultsCount; i++) {
|
|
setGuiButtonPos(resultsBtn[i + scrollOffset], 0, i * 32);
|
|
setGuiTextPos(resultsBtnTxtPlatform[i + scrollOffset], 246, i * 32 + 9);
|
|
setGuiTextPos(resultsBtnTxtRegion[i + scrollOffset], 246, i * 32 + 23);
|
|
|
|
addToGuiScreen(bottomScreen, resultsBtn[i + scrollOffset], GUI_ELEMENT_TYPE_BUTTON);
|
|
addToGuiScreen(bottomScreen, resultsBtnTxtPlatform[i + scrollOffset], GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, resultsBtnTxtRegion[i + scrollOffset], GUI_ELEMENT_TYPE_TEXT);
|
|
}
|
|
} else if (selectAction) {
|
|
resetGuiButtonState(resultsBtn[scrollOffset + selectOffset]);
|
|
|
|
if (selectUpAction && selectOffset > 0)
|
|
selectOffset--;
|
|
else if (selectDownAction && selectOffset < MAX_RESULTS_PER_PAGE - 1)
|
|
selectOffset++;
|
|
|
|
setGuiButtonState(resultsBtn[scrollOffset + selectOffset], GUI_BUTTON_STATE_SELECTED);
|
|
} else if (clickAction) {
|
|
setGuiButtonState(resultsBtn[scrollOffset + selectOffset], GUI_BUTTON_STATE_CLICKED);
|
|
} else if (switchPageAction) {
|
|
// Set page and refresh menu
|
|
if (nextPageEnabled && nextPageAction) {
|
|
searchPage++;
|
|
switchMenu(MENU_RESULTS);
|
|
} else if (prevPageEnabled && prevPageAction) {
|
|
searchPage--;
|
|
switchMenu(MENU_RESULTS);
|
|
}
|
|
} else {
|
|
// Check for clicked result, set selected entry and switch to entry menu
|
|
for (size_t i = 0; i < displayedResultsCount; i++) {
|
|
if (getGuiButtonState(resultsBtn[i + scrollOffset]) != GUI_BUTTON_STATE_CLICKED)
|
|
continue;
|
|
|
|
if (selectedEntry)
|
|
freeEntry(selectedEntry);
|
|
selectedEntry = cloneEntry(results[i + scrollOffset]);
|
|
switchMenu(MENU_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
|
|
drawScreens();
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
freeGuiText(menuTitle);
|
|
freeGuiText(prevPageTxt);
|
|
freeGuiText(nextPageTxt);
|
|
freeGuiImage(lButtonIcon);
|
|
freeGuiImage(rButtonIcon);
|
|
freeGuiBox(resultsBtnBg);
|
|
freeGuiBox(resultsBtnBgHover);
|
|
|
|
for (size_t i = 0; i < resultsCount; i++) {
|
|
freeGuiText(resultsBtnTxt[i]);
|
|
freeGuiText(resultsBtnTxtPlatform[i]);
|
|
freeGuiText(resultsBtnTxtRegion[i]);
|
|
freeGuiButton(resultsBtn[i]);
|
|
freeEntry(results[i]);
|
|
}
|
|
}
|
|
|
|
// Entry menu
|
|
// Displays the information of the selected entry
|
|
void entryMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox topBg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG_2));
|
|
GuiBox bottomBg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = NULL;
|
|
GuiImage brickColor2 = NULL;
|
|
|
|
GuiText entryTitle = newGuiText(getEntryTitle(selectedEntry), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(entryTitle, 128, 20);
|
|
setGuiTextAlignment(entryTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(entryTitle, 246);
|
|
setGuiTextWrap(entryTitle, true);
|
|
setGuiTextMaxHeight(entryTitle, 40);
|
|
|
|
GuiText entryPlatformLabel = newGuiText(tr("Platform"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
setGuiTextPos(entryPlatformLabel, 80, 46);
|
|
setGuiTextAlignment(entryPlatformLabel, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText entryPlatform = newGuiText(getEntryPlatform(selectedEntry), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(entryPlatform, 176, 46);
|
|
setGuiTextAlignment(entryPlatform, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(entryPlatform, 96);
|
|
|
|
GuiText entryRegionLabel = newGuiText(tr("Region"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
setGuiTextPos(entryRegionLabel, 80, 64);
|
|
setGuiTextAlignment(entryRegionLabel, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText entryRegion = newGuiText(getEntryRegion(selectedEntry), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(entryRegion, 176, 64);
|
|
setGuiTextAlignment(entryRegion, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(entryRegion, 96);
|
|
|
|
GuiText entryAuthorLabel = newGuiText(tr("Author"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
setGuiTextPos(entryAuthorLabel, 80, 82);
|
|
setGuiTextAlignment(entryAuthorLabel, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText entryAuthor = newGuiText(getEntryAuthor(selectedEntry), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(entryAuthor, 176, 82);
|
|
setGuiTextAlignment(entryAuthor, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(entryAuthor, 96);
|
|
|
|
GuiText entryVersionLabel = newGuiText(tr("Version"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT));
|
|
setGuiTextPos(entryVersionLabel, 80, 100);
|
|
setGuiTextAlignment(entryVersionLabel, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText entryVersion = newGuiText(getEntryVersion(selectedEntry), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(entryVersion, 176, 100);
|
|
setGuiTextAlignment(entryVersion, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(entryVersion, 96);
|
|
|
|
char downloadBtnTxtText[32];
|
|
u64 entrySize = getEntrySize(selectedEntry);
|
|
|
|
if (entrySize) {
|
|
char sizeText[16];
|
|
humanizeSize(sizeText, sizeof(sizeText), getEntrySize(selectedEntry));
|
|
snprintf(downloadBtnTxtText, sizeof(downloadBtnTxtText), "%s (%s)", tr("Download"), sizeText);
|
|
} else {
|
|
snprintf(downloadBtnTxtText, sizeof(downloadBtnTxtText), "%s", tr("Download"));
|
|
}
|
|
|
|
GuiText downloadBtnTxt = newGuiText(downloadBtnTxtText, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(downloadBtnTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiBox downloadBtnBg = newGuiBox(getGuiTextWidth(downloadBtnTxt) + 20, 34, col(COLOR_BG_2));
|
|
setGuiBoxBorder(downloadBtnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox downloadBtnBgHover = newGuiBox(getGuiTextWidth(downloadBtnTxt) + 20, 34, col(COLOR_PRIMARY));
|
|
|
|
GuiButton downloadBtn = newGuiButton(getGuiTextWidth(downloadBtnTxt) + 20, 34);
|
|
setGuiButtonPos(downloadBtn, SCREEN_WIDTH / 2 - (getGuiTextWidth(downloadBtnTxt) + 20) / 2, 114);
|
|
setGuiButtonBg(downloadBtn, downloadBtnBg, downloadBtnBgHover);
|
|
setGuiButtonLabel(downloadBtn, downloadBtnTxt);
|
|
|
|
GuiImage boxart = loadBoxart(selectedEntry);
|
|
|
|
addToGuiScreen(topScreen, topBg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
if (boxart) {
|
|
setGuiImagePos(boxart, 128, 96);
|
|
setGuiImageAlign(boxart, GUI_IMAGE_H_ALIGN_CENTER, GUI_IMAGE_V_ALIGN_MIDDLE);
|
|
|
|
addToGuiScreen(topScreen, boxart, GUI_ELEMENT_TYPE_IMAGE);
|
|
} else {
|
|
brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
}
|
|
|
|
addToGuiScreen(bottomScreen, bottomBg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, entryTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryPlatformLabel, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryPlatform, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryRegionLabel, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryRegion, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryAuthorLabel, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryAuthor, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryVersionLabel, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, entryVersion, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, downloadBtn, GUI_ELEMENT_TYPE_BUTTON);
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(downloadBtn) == GUI_BUTTON_STATE_CLICKED)
|
|
switchMenu(MENU_DOWNLOAD);
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(topBg);
|
|
freeGuiBox(bottomBg);
|
|
freeGuiText(entryTitle);
|
|
freeGuiText(entryPlatformLabel);
|
|
freeGuiText(entryPlatform);
|
|
freeGuiText(entryRegionLabel);
|
|
freeGuiText(entryRegion);
|
|
freeGuiText(entryAuthorLabel);
|
|
freeGuiText(entryAuthor);
|
|
freeGuiText(entryVersionLabel);
|
|
freeGuiText(entryVersion);
|
|
freeGuiText(downloadBtnTxt);
|
|
freeGuiBox(downloadBtnBg);
|
|
freeGuiBox(downloadBtnBgHover);
|
|
freeGuiButton(downloadBtn);
|
|
|
|
if (boxart) {
|
|
freeGuiImage(boxart);
|
|
} else {
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
}
|
|
}
|
|
|
|
// Download menu
|
|
// Starts the download of the selected entry
|
|
void downloadMenu(void)
|
|
{
|
|
downloadEntry(selectedEntry);
|
|
|
|
switchMenu(MENU_BROWSE);
|
|
}
|
|
|
|
#define MAX_DATABASES_DISPLAY 8
|
|
|
|
// Databases menu
|
|
// Displays the list of available databases
|
|
void databasesMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
GuiText menuTitle = newGuiText(tr("Databases"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(menuTitle, 128, 178);
|
|
setGuiTextAlignment(menuTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText noDatabasesTxt = newGuiText(tr("No databases found"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_3));
|
|
setGuiTextPos(noDatabasesTxt, 128, 80);
|
|
setGuiTextAlignment(noDatabasesTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(noDatabasesTxt, 244);
|
|
setGuiTextWrap(noDatabasesTxt, true);
|
|
|
|
GuiBox btnBg = newGuiBox(SCREEN_WIDTH, 20, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg, 2, col(COLOR_PRIMARY));
|
|
|
|
GuiBox btnBgUsed = newGuiBox(SCREEN_WIDTH, 20, col(COLOR_SECONDARY));
|
|
setGuiBoxBorder(btnBgUsed, 2, col(COLOR_PRIMARY));
|
|
|
|
GuiBox btnBgHover = newGuiBox(SCREEN_WIDTH, 20, col(COLOR_PRIMARY));
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, menuTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
// Get database list and create screen elements
|
|
size_t dbCount;
|
|
Database* dbList = getDatabaseList(&dbCount);
|
|
|
|
GuiText dbBtnTxtNames[dbCount];
|
|
GuiText dbBtnTxtValues[dbCount];
|
|
GuiButton dbBtns[dbCount];
|
|
|
|
for (size_t i = 0; i < dbCount && i < MAX_DATABASES_DISPLAY; i++) {
|
|
dbBtnTxtNames[i] = newGuiText(getDatabaseName(dbList[i]), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(dbBtnTxtNames[i], 10, 0);
|
|
setGuiTextAlignment(dbBtnTxtNames[i], GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(dbBtnTxtNames[i], 236);
|
|
|
|
dbBtnTxtValues[i] = newGuiText(getDatabaseValue(dbList[i]), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextPos(dbBtnTxtValues[i], 246, i * 20 + 10);
|
|
setGuiTextAlignment(dbBtnTxtValues[i], GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(dbBtnTxtValues[i], 236 - getGuiTextWidth(dbBtnTxtNames[i]));
|
|
|
|
dbBtns[i] = newGuiButton(SCREEN_WIDTH, 20);
|
|
|
|
// Use different bg color if database is being used
|
|
if (db && strcmp(getDatabaseValue(db), getDatabaseValue(dbList[i])) == 0)
|
|
setGuiButtonBg(dbBtns[i], btnBgUsed, btnBgHover);
|
|
else
|
|
setGuiButtonBg(dbBtns[i], btnBg, btnBgHover);
|
|
|
|
setGuiButtonLabel(dbBtns[i], dbBtnTxtNames[i]);
|
|
setGuiButtonPos(dbBtns[i], 0, i * 20);
|
|
|
|
addToGuiScreen(bottomScreen, dbBtns[i], GUI_ELEMENT_TYPE_BUTTON);
|
|
addToGuiScreen(bottomScreen, dbBtnTxtValues[i], GUI_ELEMENT_TYPE_TEXT);
|
|
}
|
|
|
|
if (dbCount == 0)
|
|
addToGuiScreen(bottomScreen, noDatabasesTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
for (size_t i = 0; i < dbCount; i++) {
|
|
if (getGuiButtonState(dbBtns[i]) != GUI_BUTTON_STATE_CLICKED)
|
|
continue;
|
|
|
|
Database d = dbList[i];
|
|
|
|
if (!loadDatabase(d))
|
|
freeDatabase(d);
|
|
|
|
switchMenu(MENU_DATABASES);
|
|
}
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
freeGuiText(menuTitle);
|
|
freeGuiText(noDatabasesTxt);
|
|
freeGuiBox(btnBg);
|
|
freeGuiBox(btnBgUsed);
|
|
freeGuiBox(btnBgHover);
|
|
|
|
for (size_t i = 0; i < dbCount && i < MAX_DATABASES_DISPLAY; i++) {
|
|
freeGuiText(dbBtnTxtNames[i]);
|
|
freeGuiText(dbBtnTxtValues[i]);
|
|
freeGuiButton(dbBtns[i]);
|
|
|
|
if (dbList[i] != db)
|
|
freeDatabase(dbList[i]);
|
|
}
|
|
}
|
|
|
|
// Settings menu
|
|
// Displays the app settings
|
|
void settingsMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
GuiText menuTitle = newGuiText(tr("Settings"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(menuTitle, 128, 178);
|
|
setGuiTextAlignment(menuTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiBox btnBg = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_BG_2));
|
|
setGuiBoxBorder(btnBg, 2, col(COLOR_PRIMARY));
|
|
|
|
GuiBox btnBgHover = newGuiBox(SCREEN_WIDTH, 32, col(COLOR_PRIMARY));
|
|
|
|
GuiText settingBtnTxt[SETTINGS_COUNT];
|
|
GuiButton settingBtn[SETTINGS_COUNT];
|
|
GuiText settingValueTxt[SETTINGS_COUNT];
|
|
|
|
char colorSchemeStr[4];
|
|
snprintf(colorSchemeStr, sizeof(colorSchemeStr), "%d", settings.colorScheme + 1);
|
|
|
|
settingBtnTxt[0] = newGuiText(tr("Downloads directory"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
settingValueTxt[0] = newGuiText(settings.dlPath, GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextMaxWidth(settingBtnTxt[0], 122);
|
|
|
|
settingBtnTxt[1] = newGuiText(tr("Use platform-specific directories (E.g. nds, gba)"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
settingValueTxt[1] = newGuiText(tr(dlUseDirsStr(settings.dlUseDirs)), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextMaxWidth(settingBtnTxt[1], 168);
|
|
|
|
settingBtnTxt[2] = newGuiText(tr("Color scheme"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
settingValueTxt[2] = newGuiText(colorSchemeStr, GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextMaxWidth(settingBtnTxt[2], 168);
|
|
|
|
settingBtnTxt[3] = newGuiText(tr("Check for updates on start"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
settingValueTxt[3] = newGuiText(tr(checkUpdateOnStartStr(settings.checkUpdateOnStart)), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextMaxWidth(settingBtnTxt[3], 168);
|
|
|
|
settingBtnTxt[4] = newGuiText(tr("Language"), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
settingValueTxt[4] = newGuiText(tr(langStr(settings.lang)), GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_3));
|
|
setGuiTextMaxWidth(settingBtnTxt[4], 168);
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, menuTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
|
|
for (size_t i = 0; i < SETTINGS_COUNT; i++) {
|
|
setGuiTextPos(settingBtnTxt[i], 12, 0);
|
|
setGuiTextAlignment(settingBtnTxt[i], GUI_TEXT_H_ALIGN_LEFT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxHeight(settingBtnTxt[i], 32);
|
|
setGuiTextWrap(settingBtnTxt[i], true);
|
|
|
|
setGuiTextPos(settingValueTxt[i], 244, i * 32 + 16);
|
|
setGuiTextAlignment(settingValueTxt[i], GUI_TEXT_H_ALIGN_RIGHT, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
setGuiTextMaxWidth(settingValueTxt[i], 232 - getGuiTextWidth(settingBtnTxt[i]));
|
|
setGuiTextMaxHeight(settingValueTxt[i], 32);
|
|
setGuiTextWrap(settingValueTxt[i], true);
|
|
|
|
settingBtn[i] = newGuiButton(SCREEN_WIDTH, 32);
|
|
setGuiButtonBg(settingBtn[i], btnBg, btnBgHover);
|
|
setGuiButtonLabel(settingBtn[i], settingBtnTxt[i]);
|
|
setGuiButtonPos(settingBtn[i], 0, i * 32);
|
|
|
|
addToGuiScreen(bottomScreen, settingBtn[i], GUI_ELEMENT_TYPE_BUTTON);
|
|
addToGuiScreen(bottomScreen, settingValueTxt[i], GUI_ELEMENT_TYPE_TEXT);
|
|
}
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(settingBtn[0]) == GUI_BUTTON_STATE_CLICKED) {
|
|
char tempDlPath[PATH_MAX];
|
|
strcpy(tempDlPath, settings.dlPath);
|
|
|
|
if (keyboardEdit(tempDlPath, sizeof(tempDlPath))) {
|
|
bool save = true;
|
|
|
|
if (tempDlPath[0] == '\0') {
|
|
windowPrompt(tr("Error"), tr("Path can not be empty"), tr("Ok"), NULL);
|
|
save = false;
|
|
} else if (!dirExists(tempDlPath)) {
|
|
if (windowPrompt(tr("Error"), tr("Directory does not exist. Do you want to create it?"), tr("Ok"), tr("Cancel"))) {
|
|
if (!createDirR(tempDlPath)) {
|
|
windowPrompt(tr("Error"), tr("Failed to create directory"), tr("Ok"), NULL);
|
|
save = false;
|
|
}
|
|
} else {
|
|
save = false;
|
|
}
|
|
}
|
|
|
|
if (save) {
|
|
strcpy(settings.dlPath, tempDlPath);
|
|
saveSettings();
|
|
}
|
|
}
|
|
|
|
setGuiTextText(settingValueTxt[0], settings.dlPath);
|
|
|
|
resetGuiButtonState(settingBtn[0]);
|
|
} else if (getGuiButtonState(settingBtn[1]) == GUI_BUTTON_STATE_CLICKED) {
|
|
settings.dlUseDirs = settings.dlUseDirs ? false : true;
|
|
|
|
setGuiTextText(settingValueTxt[1], tr(dlUseDirsStr(settings.dlUseDirs)));
|
|
|
|
saveSettings();
|
|
resetGuiButtonState(settingBtn[1]);
|
|
} else if (getGuiButtonState(settingBtn[2]) == GUI_BUTTON_STATE_CLICKED) {
|
|
settings.colorScheme++;
|
|
|
|
if (settings.colorScheme == COLOR_SCHEMES_COUNT)
|
|
settings.colorScheme = 0;
|
|
|
|
snprintf(colorSchemeStr, sizeof(colorSchemeStr), "%d", settings.colorScheme + 1);
|
|
setGuiTextText(settingValueTxt[2], colorSchemeStr);
|
|
|
|
freeNavbar();
|
|
initNavbar();
|
|
switchMenu(MENU_SETTINGS);
|
|
|
|
saveSettings();
|
|
resetGuiButtonState(settingBtn[2]);
|
|
} else if (getGuiButtonState(settingBtn[3]) == GUI_BUTTON_STATE_CLICKED) {
|
|
settings.checkUpdateOnStart = settings.checkUpdateOnStart ? false : true;
|
|
|
|
setGuiTextText(settingValueTxt[3], tr(checkUpdateOnStartStr(settings.checkUpdateOnStart)));
|
|
|
|
saveSettings();
|
|
resetGuiButtonState(settingBtn[3]);
|
|
} else if (getGuiButtonState(settingBtn[4]) == GUI_BUTTON_STATE_CLICKED) {
|
|
settings.lang++;
|
|
|
|
if (settings.lang == LANGS_COUNT)
|
|
settings.lang = 0;
|
|
|
|
setGuiTextText(settingValueTxt[4], tr(langStr(settings.lang)));
|
|
|
|
loadLanguage(settings.lang);
|
|
switchMenu(MENU_SETTINGS);
|
|
|
|
saveSettings();
|
|
resetGuiButtonState(settingBtn[4]);
|
|
}
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
freeGuiText(menuTitle);
|
|
freeGuiBox(btnBg);
|
|
freeGuiBox(btnBgHover);
|
|
|
|
for (size_t i = 0; i < SETTINGS_COUNT; i++) {
|
|
freeGuiText(settingBtnTxt[i]);
|
|
freeGuiText(settingValueTxt[i]);
|
|
freeGuiButton(settingBtn[i]);
|
|
}
|
|
}
|
|
|
|
// Info menu
|
|
// Displays information about Kekatsu
|
|
void infoMenu(void)
|
|
{
|
|
menu = MENU_NONE;
|
|
|
|
GuiScreen topScreen = newGuiScreen(GUI_SCREEN_LCD_TOP);
|
|
GuiScreen bottomScreen = newGuiScreen(GUI_SCREEN_LCD_BOTTOM);
|
|
|
|
GuiBox bg = newGuiBox(SCREEN_WIDTH, SCREEN_HEIGHT, col(COLOR_BG));
|
|
|
|
GuiImage brickColor1 = newGuiImage(brickColor1Bitmap, brickColor1Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
GuiImage brickColor2 = newGuiImage(brickColor2Bitmap, brickColor2Pal, 64, 48, 64, 64, 0, 0, GUI_IMAGE_TEXTURE_TYPE_RGB256);
|
|
setGuiImageColorTint(brickColor1, col(COLOR_PRIMARY));
|
|
setGuiImageColorTint(brickColor2, col(COLOR_SECONDARY));
|
|
setGuiImagePos(brickColor1, 96, 72);
|
|
setGuiImagePos(brickColor2, 96, 72);
|
|
|
|
GuiText menuTitle = newGuiText(tr("Info"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(menuTitle, 128, 178);
|
|
setGuiTextAlignment(menuTitle, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText appNameTxt = newGuiText(APP_NAME, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT));
|
|
setGuiTextPos(appNameTxt, 128, 22);
|
|
setGuiTextAlignment(appNameTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
char appVersionText[16];
|
|
snprintf(appVersionText, sizeof(appVersionText), "%s %s", tr("Version"), APP_VERSION);
|
|
|
|
GuiText appVersionTxt = newGuiText(appVersionText, GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextPos(appVersionTxt, 128, 43);
|
|
setGuiTextAlignment(appVersionTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText subtitle1Txt = newGuiText("by Cavv", GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(subtitle1Txt, 128, 72);
|
|
setGuiTextAlignment(subtitle1Txt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText subtitle2Txt = newGuiText("https://github.com/cavv-dev/Kekatsu-DS", GUI_TEXT_SIZE_SMALL, col(COLOR_TEXT_2));
|
|
setGuiTextPos(subtitle2Txt, 128, 87);
|
|
setGuiTextAlignment(subtitle2Txt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
GuiText checkUpdateBtnTxt = newGuiText(tr("Check for updates"), GUI_TEXT_SIZE_MEDIUM, col(COLOR_TEXT_2));
|
|
setGuiTextAlignment(checkUpdateBtnTxt, GUI_TEXT_H_ALIGN_CENTER, GUI_TEXT_V_ALIGN_MIDDLE);
|
|
|
|
size_t checkUpdateBtnWidth = getGuiTextWidth(checkUpdateBtnTxt) + 20;
|
|
|
|
GuiBox checkUpdateBtnBg = newGuiBox(checkUpdateBtnWidth, 34, col(COLOR_BG_2));
|
|
setGuiBoxBorder(checkUpdateBtnBg, 2, col(COLOR_PRIMARY));
|
|
GuiBox checkUpdateBtnBgHover = newGuiBox(checkUpdateBtnWidth, 32, col(COLOR_PRIMARY));
|
|
|
|
GuiButton checkUpdateBtn = newGuiButton(checkUpdateBtnWidth, 34);
|
|
setGuiButtonBg(checkUpdateBtn, checkUpdateBtnBg, checkUpdateBtnBgHover);
|
|
setGuiButtonLabel(checkUpdateBtn, checkUpdateBtnTxt);
|
|
setGuiButtonPos(checkUpdateBtn, 128 - checkUpdateBtnWidth / 2, 106);
|
|
|
|
addToGuiScreen(topScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(topScreen, brickColor1, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, brickColor2, GUI_ELEMENT_TYPE_IMAGE);
|
|
addToGuiScreen(topScreen, menuTitle, GUI_ELEMENT_TYPE_TEXT);
|
|
|
|
addToGuiScreen(bottomScreen, bg, GUI_ELEMENT_TYPE_BOX);
|
|
addToGuiScreen(bottomScreen, appNameTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, appVersionTxt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, subtitle1Txt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, subtitle2Txt, GUI_ELEMENT_TYPE_TEXT);
|
|
addToGuiScreen(bottomScreen, checkUpdateBtn, GUI_ELEMENT_TYPE_BUTTON);
|
|
|
|
addNavbarToGuiScreen(bottomScreen);
|
|
|
|
setActiveScreens(topScreen, bottomScreen);
|
|
while (pmMainLoop() && menu == MENU_NONE) {
|
|
guiLoop();
|
|
drawScreens();
|
|
|
|
if (getGuiButtonState(checkUpdateBtn) == GUI_BUTTON_STATE_CLICKED) {
|
|
handleUpdateCheck();
|
|
resetGuiButtonState(checkUpdateBtn);
|
|
}
|
|
|
|
navbarSwitchMenu();
|
|
}
|
|
|
|
freeGuiScreen(topScreen);
|
|
freeGuiScreen(bottomScreen);
|
|
freeGuiBox(bg);
|
|
freeGuiImage(brickColor1);
|
|
freeGuiImage(brickColor2);
|
|
freeGuiText(menuTitle);
|
|
freeGuiText(appNameTxt);
|
|
freeGuiText(appVersionTxt);
|
|
freeGuiText(subtitle1Txt);
|
|
freeGuiText(subtitle2Txt);
|
|
freeGuiText(checkUpdateBtnTxt);
|
|
freeGuiBox(checkUpdateBtnBg);
|
|
freeGuiBox(checkUpdateBtnBgHover);
|
|
freeGuiButton(checkUpdateBtn);
|
|
}
|
|
|
|
// Initializes the GUI elements and starts the menu system
|
|
void menuBegin(MenuEnum startingMenu)
|
|
{
|
|
drawBlank();
|
|
|
|
loadLanguage(settings.lang);
|
|
initColorSchemes();
|
|
initNavbar();
|
|
|
|
switchMenu(startingMenu);
|
|
|
|
loadLastOpenedDb();
|
|
|
|
if (settings.checkUpdateOnStart)
|
|
handleUpdateCheck();
|
|
|
|
while (menu != MENU_EXIT) {
|
|
switch (menu) {
|
|
case MENU_BROWSE:
|
|
browseMenu();
|
|
break;
|
|
case MENU_RESULTS:
|
|
resultsMenu();
|
|
break;
|
|
case MENU_ENTRY:
|
|
entryMenu();
|
|
break;
|
|
case MENU_DOWNLOAD:
|
|
downloadMenu();
|
|
break;
|
|
case MENU_DATABASES:
|
|
databasesMenu();
|
|
break;
|
|
case MENU_SETTINGS:
|
|
settingsMenu();
|
|
break;
|
|
case MENU_INFO:
|
|
infoMenu();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
drawBlank();
|
|
}
|