Fix up menus a bit

This commit is contained in:
J-D-K
2024-08-10 13:28:30 -04:00
parent 3754689251
commit 89d4472d07
22 changed files with 269 additions and 242 deletions

View File

@@ -11,7 +11,7 @@ namespace data
{
// Makes stuff easier to type.
using titleMap = std::unordered_map<uint64_t, data::titleInfo>;
// Loads users and titles from switch records. This is the initial loading routine and can run as a task.
bool init(void);
// Loads save data for users

View File

@@ -53,6 +53,5 @@ namespace data
data::userType m_UserType;
// Vector of save info for user
std::vector<data::userSaveInfo> m_UserSaveInfo;
};
}

View File

@@ -11,7 +11,6 @@ namespace data
public:
// Inits data
userSaveInfo(uint64_t titleID, const FsSaveDataInfo &saveDataInfo, const PdmPlayStatistics &playStats);
// These do not return references or pointers so they can't be changed
uint64_t getTitleID(void) const;
// Not sure how I feel about returning references, but I don't wanna make copies to get the data from these.

View File

@@ -8,6 +8,7 @@ namespace fs
class directoryListing
{
public:
directoryListing(void) = default;
// Gets and stores a listing for directoryPath
directoryListing(const std::string &directoryPath);
// This is the function that actually loads the directory list. Vector is cleared at beginning.

View File

@@ -10,7 +10,6 @@ namespace graphics
// Inits freetype2
bool init(void);
void exit(void);
// Renders text with system font
void renderText(const std::string &text, SDL_Texture *target, int x, int y, int fontSize, uint32_t color);
// Renders text, but wraps to new line if maxWidth is hit or exeeded

View File

@@ -48,6 +48,8 @@ namespace ui
bool m_ColorShift = true;
// Amount to add/subtract from color to pulse
int m_ColorMod = 0;
// Render target for menu options
graphics::sdlTexture m_OptionRenderTarget;
private:
// Vector of options

View File

@@ -27,7 +27,7 @@ namespace
const std::string POP_MESSAGE_SAVE_EMPTY = "popSaveIsEmpty";
const std::string CONFIRM_OVERWRITE = "confirmOverwrite";
const std::string CONFIRM_RESTORE = "confirmRestore";
const std::string CONFIRM_DELETE = "confirmDelete";
const std::string CONFIRM_DELETE = "confirmDelete";
const std::string BACKUP_MENU_NEW = "folderMenuNew";
const std::string SWKBD_PROMPT_TEXT = "swkbdEnterName";
}
@@ -66,7 +66,7 @@ static void createNewBackup(sys::task *task, sys::sharedTaskData sharedData)
// Set task status, cast args to backupArgs
std::shared_ptr<backupData> dataIn = std::static_pointer_cast<backupData>(sharedData);
// To do: Maybe find a better way to do this without rewriting everything
sys::progressTask *progress = reinterpret_cast<sys::progressTask *>(task);
@@ -183,14 +183,14 @@ static void restoreBackup(sys::task *task, sys::sharedTaskData sharedData)
// Get extension before we try to unzip something that isn't a zip
std::string fileExtension = stringUtil::getExtensionFromString(dataIn->source);
if(std::filesystem::is_directory(dataIn->source))
if (std::filesystem::is_directory(dataIn->source))
{
// Add trailing slash
std::string source = dataIn->source + "/";
// Get a test listing first to prevent writing an empty folder to save
fs::directoryListing testListing(source);
if(testListing.getListingCount() > 0)
if (testListing.getListingCount() > 0)
{
// Folder isn't empty, erase
fs::io::deleteDirectoryRecursively(fs::DEFAULT_SAVE_MOUNT_DEVICE);
@@ -198,12 +198,12 @@ static void restoreBackup(sys::task *task, sys::sharedTaskData sharedData)
fs::io::copyDirectoryCommit(source, fs::DEFAULT_SAVE_MOUNT_DEVICE, dataIn->journalSize, progress);
}
}
else if(std::filesystem::is_directory(dataIn->source) == false && fileExtension == "zip")
else if (std::filesystem::is_directory(dataIn->source) == false && fileExtension == "zip")
{
// Open zip for decompressing
unzFile unzip = unzOpen64(dataIn->source.c_str());
// Check if opening was successful and not empty first
if(unzip != NULL && fs::zip::zipFileIsNotEmpty(unzip))
if (unzip != NULL && fs::zip::zipFileIsNotEmpty(unzip))
{
fs::zip::copyZipToDirectory(unzip, fs::DEFAULT_SAVE_MOUNT_DEVICE, dataIn->journalSize, progress);
}
@@ -244,22 +244,21 @@ static void deleteBackup(sys::task *task, sys::sharedTaskData sharedData)
task->finished();
}
backupMenuState::backupMenuState(data::user *currentUser, data::userSaveInfo *currentUserSaveInfo, data::titleInfo *currentTitleInfo) :
m_CurrentUser(currentUser),
m_CurrentUserSaveInfo(currentUserSaveInfo),
m_CurrentTitleInfo(currentTitleInfo),
m_BackupMenuControlGuide(ui::strings::getString(FOLDER_MENU_CONTROL_GUIDE, 0)),
m_OutputBasePath(config::getWorkingDirectory() + m_CurrentTitleInfo->getPathSafeTitle() + "/"),
m_PanelWidth(graphics::systemFont::getTextWidth(m_BackupMenuControlGuide, 18)),
m_BackupPanel(std::make_unique<ui::slidePanel>(BACKUP_PANEL_NAME, m_PanelWidth + 64, ui::PANEL_SIDE_RIGHT)),
m_BackupListing(std::make_unique<fs::directoryListing>(m_OutputBasePath)),
m_SaveListing(std::make_unique<fs::directoryListing>(fs::DEFAULT_SAVE_MOUNT_DEVICE)),
m_BackupMenu(std::make_unique<ui::menu>(10, 4, m_PanelWidth + 44, 18, 6))
backupMenuState::backupMenuState(data::user *currentUser, data::userSaveInfo *currentUserSaveInfo, data::titleInfo *currentTitleInfo) : m_CurrentUser(currentUser),
m_CurrentUserSaveInfo(currentUserSaveInfo),
m_CurrentTitleInfo(currentTitleInfo),
m_BackupMenuControlGuide(ui::strings::getString(FOLDER_MENU_CONTROL_GUIDE, 0)),
m_OutputBasePath(config::getWorkingDirectory() + m_CurrentTitleInfo->getPathSafeTitle() + "/"),
m_PanelWidth(graphics::systemFont::getTextWidth(m_BackupMenuControlGuide, 18)),
m_BackupPanel(std::make_unique<ui::slidePanel>(BACKUP_PANEL_NAME, m_PanelWidth + 64, ui::PANEL_SIDE_RIGHT)),
m_BackupListing(std::make_unique<fs::directoryListing>(m_OutputBasePath)),
m_SaveListing(std::make_unique<fs::directoryListing>(fs::DEFAULT_SAVE_MOUNT_DEVICE)),
m_BackupMenu(std::make_unique<ui::menu>(10, 4, m_PanelWidth + 44, 18, 6))
{
// Make sure path exists
std::filesystem::create_directories(m_OutputBasePath);
// Render target that menu is rendered to
m_BackupMenuRenderTarget = graphics::textureManager::createTexture(BACKUP_MENU_TARGET_NAME, m_PanelWidth + 64, 720, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
m_BackupMenuRenderTarget = graphics::textureManager::createTexture(BACKUP_MENU_TARGET_NAME, m_PanelWidth + 64, 647, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
// Call this just to be sure.
backupMenuState::loadDirectoryList();
}
@@ -320,7 +319,7 @@ void backupMenuState::update(void)
// Setup confirmation arg pointer
std::shared_ptr<pathData> paths = std::make_shared<pathData>();
paths->source = m_BackupListing->getFullPathToItemAt(selected - 1); // Need to subtract one to account for 'New' option
paths->source = m_BackupListing->getFullPathToItemAt(selected - 1); // Need to subtract one to account for 'New' option
paths->journalSize = m_CurrentTitleInfo->getJournalSize(static_cast<FsSaveDataType>(m_CurrentUserSaveInfo->getSaveDataInfo().save_data_type)); // Needed to prevent commit errors
// Create confirmation

View File

@@ -13,36 +13,35 @@ namespace
constexpr int HOLD_TICKS = 1000;
// Strings used here
const std::string DIALOG_YES = "dialogYes";
const std::string DIALOG_NO = "dialogNo";
const std::string DIALOG_NO = "dialogNo";
const std::string HOLDING_TEXT = "holdingText";
}
confirmState::confirmState(const std::string &message, sys::taskFunction onConfirmation, sys::sharedTaskData sharedData, sys::taskTypes taskType) :
m_Message(message),
m_Yes(ui::strings::getString(DIALOG_YES, 0)),
m_No(ui::strings::getString(DIALOG_NO, 0)),
m_HoldTimer(std::make_unique<sys::timer>(HOLD_TICKS)),
m_OnConfirmation(onConfirmation),
m_SharedData(sharedData),
m_TaskType(taskType) { }
confirmState::confirmState(const std::string &message, sys::taskFunction onConfirmation, sys::sharedTaskData sharedData, sys::taskTypes taskType) : m_Message(message),
m_Yes(ui::strings::getString(DIALOG_YES, 0)),
m_No(ui::strings::getString(DIALOG_NO, 0)),
m_HoldTimer(std::make_unique<sys::timer>(HOLD_TICKS)),
m_OnConfirmation(onConfirmation),
m_SharedData(sharedData),
m_TaskType(taskType) {}
confirmState::~confirmState() { }
confirmState::~confirmState() {}
// To do: I don't like the way this looks, but not sure if it can get much better
void confirmState::update(void)
{
// If A is first pressed, and stage is 0, restart timer
if(sys::input::buttonDown(HidNpadButton_A) && m_HoldStage == 0)
if (sys::input::buttonDown(HidNpadButton_A) && m_HoldStage == 0)
{
m_HoldTimer->restartTimer();
}
else if(sys::input::buttonHeld(HidNpadButton_A) && m_HoldStage < 3 && m_HoldTimer->triggered())
else if (sys::input::buttonHeld(HidNpadButton_A) && m_HoldStage < 3 && m_HoldTimer->triggered())
{
// Confirmed, create new task.
if(++m_HoldStage == 3)
if (++m_HoldStage == 3)
{
// Spawn task according to m_TaskType
switch(m_TaskType)
switch (m_TaskType)
{
case sys::taskTypes::TASK_TYPE_TASK:
{
@@ -65,30 +64,30 @@ void confirmState::update(void)
switch (m_HoldStage)
{
case 0:
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 0);
}
break;
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 0);
}
break;
case 1:
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 1);
}
break;
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 1);
}
break;
case 2:
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 2);
}
break;
{
m_Yes = ui::strings::getString(HOLDING_TEXT, 2);
}
break;
}
}
}
else if(sys::input::buttonReleased(HidNpadButton_A))
else if (sys::input::buttonReleased(HidNpadButton_A))
{
m_Yes = ui::strings::getString(DIALOG_YES, 0);
}
else if(sys::input::buttonDown(HidNpadButton_B))
else if (sys::input::buttonDown(HidNpadButton_B))
{
// Party's over. Just stop
appState::deactivateState();

View File

@@ -41,14 +41,14 @@ static void backupAllUserSaves(sys::task *task, sys::sharedTaskData sharedData)
// Loop through users
int totalUserCount = data::getTotalUsers();
for(int i = 0; i < totalUserCount; i++)
for (int i = 0; i < totalUserCount; i++)
{
// Get pointer to user
data::user *currentUser = data::getUserAtPosition(i);
// Loop through titles
int totalUserGameCount = currentUser->getTotalUserSaveInfo();
for(int j = 0; j < totalUserGameCount; j++)
for (int j = 0; j < totalUserGameCount; j++)
{
// Get pointer to userSaveInfo
data::userSaveInfo *currentUserSaveInfo = currentUser->getUserSaveInfoAt(j);
@@ -60,20 +60,20 @@ static void backupAllUserSaves(sys::task *task, sys::sharedTaskData sharedData)
bool saveIsMounted = fs::mountSaveData(currentUserSaveInfo->getSaveDataInfo());
// Make sure full path for title exists
fs::createTitleDirectoryByTID(currentUserSaveInfo->getTitleID());
if(saveIsMounted && fs::directoryContainsFiles(fs::DEFAULT_SAVE_MOUNT_DEVICE) && config::getByKey(CONFIG_USE_ZIP))
if (saveIsMounted && fs::directoryContainsFiles(fs::DEFAULT_SAVE_MOUNT_DEVICE) && config::getByKey(CONFIG_USE_ZIP))
{
// Path to zip we're backing up. It's a biggin'
std::string outputZipPath = config::getWorkingDirectory() + currentTitleInfo->getPathSafeTitle() + "/" + currentUser->getPathSafeUsername() + \
std::string outputZipPath = config::getWorkingDirectory() + currentTitleInfo->getPathSafeTitle() + "/" + currentUser->getPathSafeUsername() +
" - " + stringUtil::getTimeAndDateString(stringUtil::DATE_FORMAT_YMD) + ".zip";
// Open zip
zipFile newZip = zipOpen64(outputZipPath.c_str(), 0);
// Copy to it
fs::zip::copyDirectoryToZip(fs::DEFAULT_SAVE_MOUNT_DEVICE, newZip, progress);
}
else if(saveIsMounted && fs::directoryContainsFiles(fs::DEFAULT_SAVE_MOUNT_DEVICE) && config::getByKey(CONFIG_USE_ZIP) == false)
else if (saveIsMounted && fs::directoryContainsFiles(fs::DEFAULT_SAVE_MOUNT_DEVICE) && config::getByKey(CONFIG_USE_ZIP) == false)
{
// Output path
std::string newSaveBackupPath = config::getWorkingDirectory() + currentTitleInfo->getPathSafeTitle() + "/" + currentUser->getPathSafeUsername() + \
std::string newSaveBackupPath = config::getWorkingDirectory() + currentTitleInfo->getPathSafeTitle() + "/" + currentUser->getPathSafeUsername() +
" - " + stringUtil::getTimeAndDateString(stringUtil::DATE_FORMAT_YMD) + "/";
// Make sure it exists
std::filesystem::create_directories(newSaveBackupPath);
@@ -86,10 +86,9 @@ static void backupAllUserSaves(sys::task *task, sys::sharedTaskData sharedData)
progress->finished();
}
mainMenuState::mainMenuState(void) :
m_MainControlGuide(ui::strings::getString(MAIN_MENU_CONTROL_GUIDE, 0)),
m_MainControlGuideX(1220 - graphics::systemFont::getTextWidth(m_MainControlGuide, 18)),
m_MainMenu(std::make_unique<ui::iconMenu>(50, 16, 1))
mainMenuState::mainMenuState(void) : m_MainControlGuide(ui::strings::getString(MAIN_MENU_CONTROL_GUIDE, 0)),
m_MainControlGuideX(1220 - graphics::systemFont::getTextWidth(m_MainControlGuide, 18)),
m_MainMenu(std::make_unique<ui::iconMenu>(50, 16, 1))
{
// Render target
m_RenderTarget = graphics::textureManager::createTexture(MAIN_MENU_RENDER_TARGET, 200, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
@@ -119,11 +118,11 @@ void mainMenuState::update(void)
m_MainMenu->update();
int selected = m_MainMenu->getSelected();
if(sys::input::buttonDown(HidNpadButton_A) && selected < m_UserEnd)
if (sys::input::buttonDown(HidNpadButton_A) && selected < m_UserEnd)
{
data::user *selectedUser = data::getUserAtPosition(selected);
// Normally wouldn't do this
if(selectedUser->getTotalUserSaveInfo() > 0)
if (selectedUser->getTotalUserSaveInfo() > 0)
{
std::unique_ptr<appState> titleSelection = std::make_unique<titleSelectionState>(selectedUser);
jksv::pushNewState(titleSelection);
@@ -134,12 +133,12 @@ void mainMenuState::update(void)
ui::popMessage::newMessage(noSavesMessage, ui::popMessage::POPMESSAGE_DEFAULT_TICKS);
}
}
else if(sys::input::buttonDown(HidNpadButton_Y))
else if (sys::input::buttonDown(HidNpadButton_Y))
{
// This doesn't need any input
createAndPushNewProgressState(backupAllUserSaves, nullptr);
}
else if(sys::input::buttonDown(HidNpadButton_X) && selected < m_UserEnd)
else if (sys::input::buttonDown(HidNpadButton_X) && selected < m_UserEnd)
{
// Get selected user
data::user *selectedUser = data::getUserAtPosition(selected);
@@ -159,7 +158,7 @@ void mainMenuState::render(void)
// Render render target to framebuffer
graphics::textureRender(m_RenderTarget.get(), NULL, 0, 91);
if(appState::hasFocus())
if (appState::hasFocus())
{
graphics::systemFont::renderText(m_MainControlGuide, NULL, m_MainControlGuideX, 673, 18, COLOR_WHITE);
}

View File

@@ -15,7 +15,7 @@ namespace
const double PROG_BAR_WIDTH = 648.0f;
const int PROG_BAR_X = 312;
const int PROG_BAR_Y = 471;
//static const int PROG_BAR_WIDTH = 484; Where'd this come from? Try to figure it out later...
// static const int PROG_BAR_WIDTH = 484; Where'd this come from? Try to figure it out later...
const int PROG_BAR_HEIGHT = 32;
// These are for the status string
const int STATUS_TEXT_X = PROG_DIALOG_X + 16;
@@ -27,14 +27,13 @@ namespace
const int PROGRESS_STATUS_FONT_SIZE = 18;
}
progressState::progressState(sys::taskFunction threadFunction, sys::sharedTaskData sharedData) :
m_Task(std::make_unique<sys::progressTask>(threadFunction, sharedData)) { }
progressState::progressState(sys::taskFunction threadFunction, sys::sharedTaskData sharedData) : m_Task(std::make_unique<sys::progressTask>(threadFunction, sharedData)) {}
progressState::~progressState() { }
progressState::~progressState() {}
void progressState::update(void)
{
if(m_Task->isRunning() == false)
if (m_Task->isRunning() == false)
{
appState::deactivateState();
}
@@ -63,7 +62,7 @@ void progressState::render()
graphics::renderRect(NULL, PROG_BAR_X, PROG_BAR_Y, PROG_BAR_WIDTH, PROG_BAR_HEIGHT, COLOR_BLACK);
graphics::renderRect(NULL, PROG_BAR_X, PROG_BAR_Y, m_BarWidth, PROG_BAR_HEIGHT, COLOR_GREEN);
graphics::systemFont::renderTextWrap(m_TaskStatus, NULL, STATUS_TEXT_X, STATUS_TEXT_Y, STATUS_TEXT_FONT_SIZE, STATUS_TEXT_MAX_WIDTH, COLOR_WHITE); // Status
graphics::systemFont::renderText(m_ProgressStatus, NULL, m_ProgressStatusX, PROGRESS_STATUS_Y, PROGRESS_STATUS_FONT_SIZE, COLOR_WHITE); // Actual progress
graphics::systemFont::renderText(m_ProgressStatus, NULL, m_ProgressStatusX, PROGRESS_STATUS_Y, PROGRESS_STATUS_FONT_SIZE, COLOR_WHITE); // Actual progress
}
void createAndPushNewProgressState(sys::taskFunction threadFunction, sys::sharedTaskData sharedData)

View File

@@ -12,14 +12,13 @@ namespace
static const int STATUS_TEXT_FONT_SIZE = 24;
}
taskState::taskState(sys::taskFunction threadFunction, sys::sharedTaskData sharedData) :
m_Task(std::make_unique<sys::task>(threadFunction, sharedData)) { }
taskState::taskState(sys::taskFunction threadFunction, sys::sharedTaskData sharedData) : m_Task(std::make_unique<sys::task>(threadFunction, sharedData)) {}
taskState::~taskState() { }
taskState::~taskState() {}
void taskState::update(void)
{
if(m_Task->isRunning() == false)
if (m_Task->isRunning() == false)
{
appState::deactivateState();
}
@@ -33,7 +32,7 @@ void taskState::render(void)
// Render glyph in bottom left corner
ui::renderLoadingGlyph();
// Dim background and render text to screen
graphics::renderRect(NULL, 0, 0, 1280, 720, COLOR_DIM_BACKGROUND);
graphics::systemFont::renderText(taskStatus, NULL, taskStatusX, STATUS_TEXT_Y, STATUS_TEXT_FONT_SIZE, COLOR_WHITE);

View File

@@ -57,7 +57,7 @@ struct titleOptsData : sys::taskData
// This was needed to debug something. Only one for now.
void resetSaveData(sys::task *task, sys::sharedTaskData sharedData)
{
if(sharedData == nullptr)
if (sharedData == nullptr)
{
task->finished();
return;
@@ -68,11 +68,11 @@ void resetSaveData(sys::task *task, sys::sharedTaskData sharedData)
// Set status
task->setThreadStatus(ui::strings::getString(THREAD_STATUS_RESETTING_SAVE, 0));
// Cast args
std::shared_ptr<titleOptsData> dataIn = std::static_pointer_cast<titleOptsData>(sharedData);
if(fs::mountSaveData(dataIn->currentUserSaveInfo->getSaveDataInfo()))
if (fs::mountSaveData(dataIn->currentUserSaveInfo->getSaveDataInfo()))
{
// Erase save data in container
// To do: remove_all keeps failing if the folder has sub dirs. Maybe I should just stick with my own?
@@ -94,21 +94,20 @@ void resetSaveData(sys::task *task, sys::sharedTaskData sharedData)
task->finished();
}
titleOptionState::titleOptionState(data::user *currentUser, data::userSaveInfo *currentUserSaveInfo, data::titleInfo *currentTitleInfo) :
m_CurrentUser(currentUser),
m_CurrentUserSaveInfo(currentUserSaveInfo),
m_CurrentTitleInfo(currentTitleInfo),
m_SlidePanel(std::make_unique<ui::slidePanel>(PANEL_RENDER_TARGET_NAME, PANEL_WIDTH, ui::PANEL_SIDE_RIGHT)),
m_OptionsMenu(std::make_unique<ui::menu>(MENU_X, MENU_Y, MENU_WIDTH, MENU_FONT_SIZE, MENU_SCROLL_LENGTH))
titleOptionState::titleOptionState(data::user *currentUser, data::userSaveInfo *currentUserSaveInfo, data::titleInfo *currentTitleInfo) : m_CurrentUser(currentUser),
m_CurrentUserSaveInfo(currentUserSaveInfo),
m_CurrentTitleInfo(currentTitleInfo),
m_SlidePanel(std::make_unique<ui::slidePanel>(PANEL_RENDER_TARGET_NAME, PANEL_WIDTH, ui::PANEL_SIDE_RIGHT)),
m_OptionsMenu(std::make_unique<ui::menu>(MENU_X, MENU_Y, MENU_WIDTH, MENU_FONT_SIZE, MENU_SCROLL_LENGTH))
{
// Setup menu
for(int i = 0; i < 9; i++)
for (int i = 0; i < 9; i++)
{
m_OptionsMenu->addOption(ui::strings::getString(TITLE_OPTIONS_MENU_STRINGS, i));
}
}
titleOptionState::~titleOptionState() { }
titleOptionState::~titleOptionState() {}
void titleOptionState::update(void)
{
@@ -116,9 +115,9 @@ void titleOptionState::update(void)
m_SlidePanel->update();
m_OptionsMenu->update();
if(sys::input::buttonDown(HidNpadButton_A))
if (sys::input::buttonDown(HidNpadButton_A))
{
switch(m_OptionsMenu->getSelected())
switch (m_OptionsMenu->getSelected())
{
// This is needed to debug something... and itself.
case RESET_SAVE_DATA:
@@ -142,11 +141,11 @@ void titleOptionState::update(void)
break;
}
}
else if(sys::input::buttonDown(HidNpadButton_B))
else if (sys::input::buttonDown(HidNpadButton_B))
{
m_SlidePanel->closePanel();
}
else if(m_SlidePanel->isClosed())
else if (m_SlidePanel->isClosed())
{
appState::deactivateState();
}

View File

@@ -18,11 +18,10 @@ namespace
const std::string TITLE_SELECTION_CONTROL_GUIDE = "helpTitle";
}
titleSelectionState::titleSelectionState(data::user *currentUser) :
m_CurrentUser(currentUser),
m_TitleSelection(std::make_unique<ui::titleSelection>(m_CurrentUser)),
m_TitleControlGuide(ui::strings::getString(TITLE_SELECTION_CONTROL_GUIDE, 0)),
m_TitleControlGuideX(1220 - graphics::systemFont::getTextWidth(m_TitleControlGuide, 18))
titleSelectionState::titleSelectionState(data::user *currentUser) : m_CurrentUser(currentUser),
m_TitleSelection(std::make_unique<ui::titleSelection>(m_CurrentUser)),
m_TitleControlGuide(ui::strings::getString(TITLE_SELECTION_CONTROL_GUIDE, 0)),
m_TitleControlGuideX(1220 - graphics::systemFont::getTextWidth(m_TitleControlGuide, 18))
{
// Render target to render everything too
m_RenderTarget = graphics::textureManager::createTexture(TITLE_SELECT_RENDER_TARGET, 1080, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
@@ -34,13 +33,13 @@ void titleSelectionState::update(void)
{
m_TitleSelection->update();
if(sys::input::buttonDown(HidNpadButton_A))
if (sys::input::buttonDown(HidNpadButton_A))
{
int selected = m_TitleSelection->getSelected();
data::userSaveInfo *currentUserSaveInfo = m_CurrentUser->getUserSaveInfoAt(selected);
if(fs::mountSaveData(currentUserSaveInfo->getSaveDataInfo()))
if (fs::mountSaveData(currentUserSaveInfo->getSaveDataInfo()))
{
data::titleInfo *currentTitleInfo = data::getTitleInfoByTitleID(currentUserSaveInfo->getTitleID());
data::titleInfo *currentTitleInfo = data::getTitleInfoByTitleID(currentUserSaveInfo->getTitleID());
std::unique_ptr<appState> backupState = std::make_unique<backupMenuState>(m_CurrentUser, currentUserSaveInfo, currentTitleInfo);
jksv::pushNewState(backupState);
}
@@ -49,7 +48,7 @@ void titleSelectionState::update(void)
logger::log("Error mounting save for %016lX", currentUserSaveInfo->getTitleID());
}
}
else if(sys::input::buttonDown(HidNpadButton_X))
else if (sys::input::buttonDown(HidNpadButton_X))
{
// Get some stuff needed
int selected = m_TitleSelection->getSelected();
@@ -61,7 +60,7 @@ void titleSelectionState::update(void)
// Push it
jksv::pushNewState(optionState);
}
else if(sys::input::buttonDown(HidNpadButton_B))
else if (sys::input::buttonDown(HidNpadButton_B))
{
appState::deactivateState();
}
@@ -77,7 +76,7 @@ void titleSelectionState::render(void)
// Render to screen
graphics::textureRender(m_RenderTarget.get(), NULL, 201, 91);
if(appState::hasFocus())
if (appState::hasFocus())
{
graphics::systemFont::renderText(m_TitleControlGuide, NULL, m_TitleControlGuideX, 673, 18, COLOR_WHITE);
}

View File

@@ -1,6 +1,7 @@
#include "appStates/userOptionState.hpp"
#include "appStates/progressState.hpp"
#include "appStates/saveCreateState.hpp"
#include "appStates/confirmState.hpp"
#include "system/progressTask.hpp"
#include "filesystem/filesystem.hpp"
#include "jksv.hpp"
@@ -17,6 +18,7 @@ namespace
const std::string OPTION_MENU_STRING_NAME = "userOptions";
const std::string THREAD_STATUS_CREATING_SAVE_DATA = "threadStatusCreatingSaveData";
const std::string THREAD_STATUS_DELETING_SAVE_DATA = "threadStatusDeletingSaveData";
const std::string CONFIRM_DELETE_ALL_USER_SAVES = "saveDataDeleteAllUser";
// Enum for menu opts
enum
{
@@ -81,7 +83,7 @@ void dumpAllForUser(sys::task *task, sys::sharedTaskData sharedData)
void createAllSaveDataForUser(sys::task *task, sys::sharedTaskData sharedData)
{
if(sharedData == nullptr)
if (sharedData == nullptr)
{
task->finished();
return;
@@ -94,9 +96,9 @@ void createAllSaveDataForUser(sys::task *task, sys::sharedTaskData sharedData)
data::titleMap &titleMap = data::getTitleMap();
// Loop through map. Have to be careful though.
for(auto &currentTitle : titleMap)
for (auto &currentTitle : titleMap)
{
if(dataIn->currentUser->getUserType() == data::userType::TYPE_USER && currentTitle.second.hasAccountSaveData())
if (dataIn->currentUser->getUserType() == data::userType::TYPE_USER && currentTitle.second.hasAccountSaveData())
{
// Set status string.
std::string threadStatus = stringUtil::getFormattedString(ui::strings::getCString(THREAD_STATUS_CREATING_SAVE_DATA, 0), currentTitle.second.getTitle().c_str());
@@ -114,7 +116,7 @@ void createAllSaveDataForUser(sys::task *task, sys::sharedTaskData sharedData)
void deleteAllSaveDataForUser(sys::task *task, sys::sharedTaskData sharedData)
{
if(sharedData == nullptr)
if (sharedData == nullptr)
{
task->finished();
return;
@@ -124,7 +126,7 @@ void deleteAllSaveDataForUser(sys::task *task, sys::sharedTaskData sharedData)
// Loop through and nuke them
int totalUserSaves = dataIn->currentUser->getTotalUserSaveInfo();
for(int i = 0; i < totalUserSaves; i++)
for (int i = 0; i < totalUserSaves; i++)
{
// Save info is needed first for titleID
data::userSaveInfo *currentUserSaveInfo = dataIn->currentUser->getUserSaveInfoAt(i);
@@ -171,60 +173,75 @@ void userOptionState::update(void)
{
switch (m_OptionsMenu->getSelected())
{
case OPTION_BACKUP_ALL_FOR_USER:
{
// Data to send
std::shared_ptr<userOptionData> optionsData = std::make_shared<userOptionData>();
optionsData->currentUser = m_CurrentUser;
// Push new state/task
createAndPushNewProgressState(dumpAllForUser, optionsData);
}
break;
case OPTION_BACKUP_ALL_FOR_USER:
{
// Data to send
std::shared_ptr<userOptionData> optionsData = std::make_shared<userOptionData>();
optionsData->currentUser = m_CurrentUser;
// Push new state/task
createAndPushNewProgressState(dumpAllForUser, optionsData);
}
break;
case OPTION_CREATE_SAVE_DATA:
case OPTION_CREATE_SAVE_DATA:
{
// What save type we're working with. Using UserID to figure it out.
FsSaveDataType saveDataType;
switch (m_CurrentUser->getAccountIDU128())
{
// What save type we're working with. Using UserID to figure it out.
FsSaveDataType saveDataType;
if (m_CurrentUser->getAccountIDU128() == 2)
case 2:
{
saveDataType = FsSaveDataType_Bcat;
}
else if (m_CurrentUser->getAccountIDU128() == 3)
break;
case 3:
{
saveDataType = FsSaveDataType_Device;
}
else if (m_CurrentUser->getAccountIDU128() == 5)
break;
case 5:
{
saveDataType = FsSaveDataType_Cache;
}
else
break;
default:
{
saveDataType = FsSaveDataType_Account;
}
// Push the state
std::unique_ptr<appState> saveCreationState = std::make_unique<saveCreateState>(m_CurrentUser, saveDataType);
jksv::pushNewState(saveCreationState);
break;
}
break;
case OPTION_CREATE_ALL_SAVE_DATA: // This needs to be fixed up...
{
std::shared_ptr<userOptionData> userData = std::make_shared<userOptionData>();
userData->currentUser = m_CurrentUser;
// Push the state
std::unique_ptr<appState> saveCreationState = std::make_unique<saveCreateState>(m_CurrentUser, saveDataType);
jksv::pushNewState(saveCreationState);
}
break;
createAndPushNewTask(createAllSaveDataForUser, userData);
}
break;
case OPTION_CREATE_ALL_SAVE_DATA: // This needs to be fixed up...
{
std::shared_ptr<userOptionData> userData = std::make_shared<userOptionData>();
userData->currentUser = m_CurrentUser;
case OPTION_DELETE_ALL_SAVES_FOR_USER:
{
std::shared_ptr<userOptionData> userData = std::make_shared<userOptionData>();
userData->currentUser = m_CurrentUser;
createAndPushNewTask(createAllSaveDataForUser, userData);
}
break;
createAndPushNewTask(deleteAllSaveDataForUser, userData);
}
break;
case OPTION_DELETE_ALL_SAVES_FOR_USER:
{
// Create confirmation string
std::string confirmDeleteAll = stringUtil::getFormattedString(ui::strings::getCString(CONFIRM_DELETE_ALL_USER_SAVES, 0), m_CurrentUser->getUsername().c_str());
// Shared data
std::shared_ptr<userOptionData> userData = std::make_shared<userOptionData>();
userData->currentUser = m_CurrentUser;
// Confirm it first.
confirmAction(confirmDeleteAll, deleteAllSaveDataForUser, userData, sys::taskTypes::TASK_TYPE_TASK);
}
break;
}
}
else if (sys::input::buttonDown(HidNpadButton_B))

View File

@@ -42,14 +42,15 @@ static u128 accountUIDToU128(AccountUid accountID)
// Same as above, but reversed
static AccountUid u128ToAccountUID(u128 accountID)
{
return (AccountUid){ (uint64_t)(accountID >> 64), (uint64_t)accountID };
return (AccountUid){(uint64_t)(accountID >> 64), (uint64_t)accountID};
}
// Checks if user exists in vector
static bool userExistsInVector(u128 accountID)
{
// This is kind of hard to follow, but search the vector and see if accountID exists
auto findUser = std::find_if(s_UserVector.begin(), s_UserVector.end(), [accountID] ( const userIDPair &userPair ) { return userPair.first == accountID; } );
auto findUser = std::find_if(s_UserVector.begin(), s_UserVector.end(), [accountID](const userIDPair &userPair)
{ return userPair.first == accountID; });
return findUser != s_UserVector.end();
}
@@ -74,7 +75,7 @@ static bool isAccountSystemSave(const FsSaveDataInfo &saveDataInfo)
{
uint8_t saveDataType = saveDataInfo.save_data_type;
u128 accountID = accountUIDToU128(saveDataInfo.uid);
if(saveDataType == FsSaveDataType_System && accountID != 0)
if (saveDataType == FsSaveDataType_System && accountID != 0)
{
return true;
}
@@ -114,7 +115,7 @@ bool data::init(void)
NsApplicationRecord currentRecord;
int entryCount = 0;
int entryOffset = 0;
while(R_SUCCEEDED(nsListApplicationRecord(&currentRecord, 1, entryOffset++, &entryCount)) && entryCount > 0)
while (R_SUCCEEDED(nsListApplicationRecord(&currentRecord, 1, entryOffset++, &entryCount)) && entryCount > 0)
{
// This is logged for when JKSV gets stuck on things
logger::log("Add title 0x%016lX.", currentRecord.application_id);
@@ -127,7 +128,7 @@ bool data::init(void)
void data::loadUserSaveInfo(void)
{
// Clear userSaveInfo before JIC
for(auto &u : s_UserVector)
for (auto &u : s_UserVector)
{
u.second.clearUserSaveInfo();
}
@@ -138,18 +139,18 @@ void data::loadUserSaveInfo(void)
int64_t entries = 0;
Result openSaveInfoReader = fsOpenSaveDataInfoReader(&saveDataInfoReader, FsSaveDataSpaceId_All);
if(R_FAILED(openSaveInfoReader))
if (R_FAILED(openSaveInfoReader))
{
logger::log("fsOpenSaveDataInfoReader failed: 0x%X", openSaveInfoReader);
return;
}
// Loop and load all saves and push them to users
while(R_SUCCEEDED(fsSaveDataInfoReaderRead(&saveDataInfoReader, &saveDataInfo, 1, &entries)) && entries > 0)
while (R_SUCCEEDED(fsSaveDataInfoReaderRead(&saveDataInfoReader, &saveDataInfo, 1, &entries)) && entries > 0)
{
// Title id depends on save type
uint64_t titleID = 0;
if(saveDataInfo.save_data_type == FsSaveDataType_System || saveDataInfo.save_data_type == FsSaveDataType_SystemBcat)
if (saveDataInfo.save_data_type == FsSaveDataType_System || saveDataInfo.save_data_type == FsSaveDataType_SystemBcat)
{
titleID = saveDataInfo.system_save_data_id;
}
@@ -159,14 +160,14 @@ void data::loadUserSaveInfo(void)
}
// Just in case it doesn't have and entry
if(titleIsLoadedInMap(titleID) == false)
if (titleIsLoadedInMap(titleID) == false)
{
logger::log("Save found for for title not in records: 0x%016lX", titleID);
s_TitleMap.emplace(std::make_pair(titleID, data::titleInfo(titleID)));
}
// Just skip this stuff. Comes after above JIC we need to load something.
if(isAccountSystemSave(saveDataInfo) && config::getByKey(CONFIG_LIST_ACCOUNT_SYSTEM_SAVES) == false)
if (isAccountSystemSave(saveDataInfo) && config::getByKey(CONFIG_LIST_ACCOUNT_SYSTEM_SAVES) == false)
{
continue;
}
@@ -189,7 +190,7 @@ void data::loadUserSaveInfo(void)
case FsSaveDataType_Temporary:
{
// This is special for compatibility just in case.
if(userExistsInVector(TEMPORARY_SAVE_USER_ID) == false)
if (userExistsInVector(TEMPORARY_SAVE_USER_ID) == false)
{
createAddSystemUser(TEMPORARY_SAVE_USER_ID);
}
@@ -206,7 +207,7 @@ void data::loadUserSaveInfo(void)
// I've never seen this used before...
case FsSaveDataType_SystemBcat:
{
if(userExistsInVector(SYSTEM_BCAT_USER_ID) == false)
if (userExistsInVector(SYSTEM_BCAT_USER_ID) == false)
{
createAddSystemUser(SYSTEM_BCAT_USER_ID);
}
@@ -217,7 +218,7 @@ void data::loadUserSaveInfo(void)
// Play stats
PdmPlayStatistics playStatistics;
if(saveDataInfo.save_data_type == FsSaveDataType_Account || saveDataInfo.save_data_type == FsSaveDataType_Device)
if (saveDataInfo.save_data_type == FsSaveDataType_Account || saveDataInfo.save_data_type == FsSaveDataType_Device)
{
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(titleID, saveDataInfo.uid, false, &playStatistics);
}
@@ -228,7 +229,7 @@ void data::loadUserSaveInfo(void)
// Finally push it to user
data::user *targetUser = data::getUserByAccountID(accountUIDToU128(saveDataInfo.uid));
if(targetUser != NULL)
if (targetUser != NULL)
{
targetUser->addNewUserSaveInfo(titleID, saveDataInfo, playStatistics);
}
@@ -240,7 +241,7 @@ void data::loadUserSaveInfo(void)
void data::sortUserSaveInfo(void)
{
for(userIDPair &userPair : s_UserVector)
for (userIDPair &userPair : s_UserVector)
{
userPair.second.sortUserSaveInfo();
}
@@ -253,8 +254,9 @@ int data::getTotalUsers(void)
data::user *data::getUserByAccountID(u128 accountID)
{
auto userPosition = std::find_if(s_UserVector.begin(), s_UserVector.end(), [accountID](const userIDPair &u){ return u.first == accountID; });
if(userPosition != s_UserVector.end())
auto userPosition = std::find_if(s_UserVector.begin(), s_UserVector.end(), [accountID](const userIDPair &u)
{ return u.first == accountID; });
if (userPosition != s_UserVector.end())
{
return &userPosition->second;
}
@@ -263,7 +265,7 @@ data::user *data::getUserByAccountID(u128 accountID)
data::user *data::getUserAtPosition(int position)
{
if(position >= 0 && position < static_cast<int>(s_UserVector.size()))
if (position >= 0 && position < static_cast<int>(s_UserVector.size()))
{
return &s_UserVector.at(position).second;
}
@@ -282,7 +284,7 @@ int data::getTotalTitleCount(void)
data::titleInfo *data::getTitleInfoByTitleID(uint64_t titleID)
{
if(s_TitleMap.find(titleID) != s_TitleMap.end())
if (s_TitleMap.find(titleID) != s_TitleMap.end())
{
return &s_TitleMap.at(titleID);
}

View File

@@ -9,8 +9,7 @@
#include "stringUtil.hpp"
#include "log.hpp"
data::titleInfo::titleInfo(uint64_t titleID) :
m_TitleID(titleID)
data::titleInfo::titleInfo(uint64_t titleID) : m_TitleID(titleID)
{
// This is the size of the control data. Used for getting icon size
uint64_t nsAppControlSize = 0;
@@ -22,7 +21,7 @@ m_TitleID(titleID)
std::string titleIDHexString = stringUtil::getFormattedString("%016lX", m_TitleID);
Result nsAppControlRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, m_TitleID, nsAppConrolData.get(), sizeof(NsApplicationControlData), &nsAppControlSize);
if(R_SUCCEEDED(nsAppControlRes) && !(nsAppControlSize < sizeof(nsAppConrolData->nacp)))
if (R_SUCCEEDED(nsAppControlRes) && !(nsAppControlSize < sizeof(nsAppConrolData->nacp)))
{
appIconSize = nsAppControlSize - sizeof(nsAppConrolData->nacp);
@@ -49,7 +48,7 @@ std::string data::titleInfo::getTitle(void)
NacpLanguageEntry *entry;
nacpGetLanguageEntry(&m_Nacp, &entry);
// If it fails, return title ID as hex string
if(entry == NULL)
if (entry == NULL)
{
return stringUtil::getFormattedString("%016lX", m_TitleID);
}
@@ -62,7 +61,7 @@ std::string data::titleInfo::getPathSafeTitle(void)
// Try to get a pathSafeTitle
std::string pathSafeTitle = stringUtil::getPathSafeString(data::titleInfo::getTitle());
// If that fails, it will be empty. Just return ID hex string
if(pathSafeTitle.empty())
if (pathSafeTitle.empty())
{
return stringUtil::getFormattedString("%016lX", m_TitleID);
}
@@ -77,7 +76,7 @@ graphics::sdlTexture data::titleInfo::getIcon(void)
int64_t data::titleInfo::getSaveDataSize(FsSaveDataType saveType)
{
int64_t saveDataSize = 0;
switch(saveType)
switch (saveType)
{
case FsSaveDataType_Account:
{
@@ -110,7 +109,7 @@ int64_t data::titleInfo::getSaveDataSizeMax(FsSaveDataType saveType)
int64_t saveSize = 0;
int64_t saveSizeMax = 0;
switch(saveType)
switch (saveType)
{
case FsSaveDataType_Account:
{
@@ -148,7 +147,7 @@ int64_t data::titleInfo::getJournalSize(FsSaveDataType saveType)
int64_t journalSize = 0;
// Different save types have different journal limits
switch(saveType)
switch (saveType)
{
case FsSaveDataType_Account:
{

View File

@@ -30,39 +30,39 @@ bool compareTitles(const data::userSaveInfo &a, const data::userSaveInfo &b)
data::titleInfo *titleInfoB = data::getTitleInfoByTitleID(b.getTitleID());
switch (config::getByKey(CONFIG_TITLE_SORT_TYPE))
{
case config::SORT_TYPE_ALPHA:
{
uint32_t codepointA, codepointB;
std::string titleA = titleInfoA->getTitle();
std::string titleB = titleInfoB->getTitle();
int titleLength = titleA.length();
for (int i = 0, j = 0; i < titleLength;)
case config::SORT_TYPE_ALPHA:
{
ssize_t aCount = decode_utf8(&codepointA, reinterpret_cast<const uint8_t *>(&titleA.c_str()[i]));
ssize_t bCount = decode_utf8(&codepointB, reinterpret_cast<const uint8_t *>(&titleB.c_str()[j]));
codepointA = std::tolower(codepointA);
codepointB = std::tolower(codepointB);
if (codepointA != codepointB)
uint32_t codepointA, codepointB;
std::string titleA = titleInfoA->getTitle();
std::string titleB = titleInfoB->getTitle();
int titleLength = titleA.length();
for (int i = 0, j = 0; i < titleLength;)
{
return codepointA < codepointB;
ssize_t aCount = decode_utf8(&codepointA, reinterpret_cast<const uint8_t *>(&titleA.c_str()[i]));
ssize_t bCount = decode_utf8(&codepointB, reinterpret_cast<const uint8_t *>(&titleB.c_str()[j]));
codepointA = std::tolower(codepointA);
codepointB = std::tolower(codepointB);
if (codepointA != codepointB)
{
return codepointA < codepointB;
}
i += aCount;
j += bCount;
}
i += aCount;
j += bCount;
}
}
break;
break;
case config::SORT_TYPE_MOST_PLAYED:
{
return a.getPlayStatistics().playtime > b.getPlayStatistics().playtime;
}
break;
case config::SORT_TYPE_MOST_PLAYED:
{
return a.getPlayStatistics().playtime > b.getPlayStatistics().playtime;
}
break;
case config::SORT_TYPE_LAST_PLAYED:
{
return a.getPlayStatistics().last_timestamp_user > b.getPlayStatistics().last_timestamp_user;
}
break;
case config::SORT_TYPE_LAST_PLAYED:
{
return a.getPlayStatistics().last_timestamp_user > b.getPlayStatistics().last_timestamp_user;
}
break;
}
return false;
}
@@ -115,10 +115,10 @@ data::user::user(AccountUid accountID, data::userType userType) : m_AccountID(ac
}
data::user::user(AccountUid accountID, const std::string &username, const std::string &pathSafeUsername, data::userType userType) : m_AccountID(accountID),
m_Username(username),
m_PathSafeUsername(pathSafeUsername),
m_Icon(graphics::createIcon(m_Username, m_Username, 42)),
m_UserType(userType) {}
m_Username(username),
m_PathSafeUsername(pathSafeUsername),
m_Icon(graphics::createIcon(m_Username, m_Username, 42)),
m_UserType(userType) {}
void data::user::addNewUserSaveInfo(uint64_t titleID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats)
{
@@ -160,7 +160,7 @@ graphics::sdlTexture data::user::getUserIcon(void) const
return m_Icon;
}
data::userType data::user::getUserType(void) const
data::userType data::user::getUserType(void) const
{
return m_UserType;
}

View File

@@ -1,9 +1,8 @@
#include "data/userSaveInfo.hpp"
data::userSaveInfo::userSaveInfo(uint64_t titleID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats) :
m_TitleID(titleID),
m_SaveDataInfo(saveInfo),
m_PlayStats(playStats) { }
data::userSaveInfo::userSaveInfo(uint64_t titleID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats) : m_TitleID(titleID),
m_SaveDataInfo(saveInfo),
m_PlayStats(playStats) {}
uint64_t data::userSaveInfo::getTitleID(void) const
{

View File

@@ -5,8 +5,7 @@
#include "stringUtil.hpp"
#include "log.hpp"
fs::directoryListing::directoryListing(const std::string &directoryPath) :
m_DirectoryPath(directoryPath)
fs::directoryListing::directoryListing(const std::string &directoryPath) : m_DirectoryPath(directoryPath)
{
loadListing();
}
@@ -19,7 +18,7 @@ void fs::directoryListing::loadListing(void)
// Error code
std::error_code errorCode;
for(const std::filesystem::directory_entry &entry : std::filesystem::directory_iterator(m_DirectoryPath, errorCode))
for (const std::filesystem::directory_entry &entry : std::filesystem::directory_iterator(m_DirectoryPath, errorCode))
{
m_DirectoryList.push_back(entry);
}

View File

@@ -142,8 +142,8 @@ bool fs::createSaveDataFileSystem(FsSaveDataType saveType, uint64_t titleID, Acc
FsSaveDataMetaInfo saveMetaInfo =
{
.size = saveType == FsSaveDataType_Bcat ? 0 : 0x40060,
.type = saveType == FsSaveDataType_Bcat ? 0 : FsSaveDataMetaType_Thumbnail
.size = saveType == FsSaveDataType_Bcat ? static_cast<uint32_t>(0) : static_cast<uint32_t>(0x40060),
.type = saveType == FsSaveDataType_Bcat ? static_cast<uint8_t>(0) : static_cast<uint8_t>(FsSaveDataMetaType_Thumbnail)
};
Result createSaveResult = fsCreateSaveDataFileSystem(&saveDataAttributes, &saveCreationInfo, &saveMetaInfo);

View File

@@ -31,15 +31,12 @@ namespace
FT_Face s_FTFaces[6];
//Number of fonts loaded
int s_TotalFonts;
// Color used for rendering. Added to prevent duplicating code.
uint32_t s_RenderingColor;
// This is the glyph texture cache map
std::map<std::pair<uint32_t, int>, glyphData> s_GlyphMap;
// How large the word buffer is for line wrapping.
const int WORD_WRAP_BUFFER_LENGTH = 0x1000;
// Masks for converting glyphs to sdl surface
const uint32_t s_RedMask = 0xFF000000;
const uint32_t s_GreenMask = 0x00FF0000;
const uint32_t s_BlueMask = 0x0000FF00;
const uint32_t s_AlphaMask = 0x000000FF;
// Codepoints to break lines at
const std::array<uint32_t, 7> s_BreakPoints = {L' ', L' ', L'/', L'_', L'-', L'。', L'、'};
}
@@ -99,7 +96,7 @@ static glyphData *getGlyph(uint32_t codepoint, int fontSize)
}
// Create Temporary SDL_Surface to convert to texture
SDL_Surface *tempGlyphSurface = SDL_CreateRGBSurfaceFrom(glyphPixelData.data(), bitmap.width, bitmap.rows, 32, sizeof(uint32_t) * bitmap.width, s_RedMask, s_GreenMask, s_BlueMask, s_AlphaMask);
SDL_Surface *tempGlyphSurface = SDL_CreateRGBSurfaceFrom(glyphPixelData.data(), bitmap.width, bitmap.rows, 32, sizeof(uint32_t) * bitmap.width, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
// Texture manager needs name for texture.
std::string glyphName = std::to_string(codepoint) + "_" + std::to_string(fontSize);
@@ -153,32 +150,33 @@ static size_t findNextBreakPoint(const char *str)
}
//Processes characters set to change text colors. Returns true if character is special
static bool processSpecialCharacters(uint32_t codepoint, uint32_t originalColor, uint32_t &color)
static bool processSpecialCharacters(uint32_t codepoint, uint32_t originalColor)
{
// This is set to true and on default, set to false.
bool isSpecial = true;
switch (codepoint)
{
case L'#':
{
color = color == COLOR_BLUE ? originalColor : COLOR_BLUE;
s_RenderingColor = s_RenderingColor == originalColor ? COLOR_BLUE : originalColor;
}
break;
case L'*':
{
color = color == COLOR_RED ? originalColor : COLOR_RED;
s_RenderingColor = s_RenderingColor == originalColor ? COLOR_RED : originalColor;
}
break;
case L'<':
{
color = color == COLOR_YELLOW ? originalColor : COLOR_YELLOW;
s_RenderingColor = s_RenderingColor == originalColor ? COLOR_YELLOW : originalColor;
}
break;
case L'>':
{
color = color == COLOR_GREEN ? originalColor : COLOR_GREEN;
s_RenderingColor = s_RenderingColor == originalColor ? COLOR_GREEN : originalColor;
}
break;
@@ -188,6 +186,7 @@ static bool processSpecialCharacters(uint32_t codepoint, uint32_t originalColor,
}
break;
}
return isSpecial;
}
@@ -249,7 +248,7 @@ void graphics::systemFont::renderText(const std::string &text, SDL_Texture *targ
int workingY = y;
//Color we're working with
uint32_t workingColor = color;
s_RenderingColor = color;
//Current character/codepoint
uint32_t codepoint = 0;
@@ -272,7 +271,7 @@ void graphics::systemFont::renderText(const std::string &text, SDL_Texture *targ
}
i += unitCount;
if(processSpecialCharacters(codepoint, color, workingColor))
if(processSpecialCharacters(codepoint, color))
{
continue;
}
@@ -288,7 +287,7 @@ void graphics::systemFont::renderText(const std::string &text, SDL_Texture *targ
if(glyph)
{
// Set color just to be sure
SDL_SetTextureColorMod(glyph->glyph.get(), getRed(workingColor), getGreen(workingColor), getBlue(workingColor));
SDL_SetTextureColorMod(glyph->glyph.get(), getRed(s_RenderingColor), getGreen(s_RenderingColor), getBlue(s_RenderingColor));
// Render glyph texture
graphics::textureRender(glyph->glyph.get(), target, workingX + glyph->left, workingY + (fontSize - glyph->top));
// X update
@@ -303,6 +302,7 @@ void graphics::systemFont::renderTextWrap(const std::string &text, SDL_Texture *
int workingX = x;
int workingY = y;
int stringLength = text.length();
// This buffer is used to calculate if the next word should create a line break
std::array<char, WORD_WRAP_BUFFER_LENGTH> wordBuffer = { 0 };
@@ -338,7 +338,6 @@ int graphics::systemFont::getTextWidth(const std::string &text, int fontSize)
{
int textWidth = 0;
uint32_t codepoint = 0;
uint32_t colorMod = 0; // This is just needed so we can properly count and skip special chars
ssize_t unitCount = 0;
resizeFont(fontSize);
@@ -352,7 +351,7 @@ int graphics::systemFont::getTextWidth(const std::string &text, int fontSize)
}
i += unitCount;
if(processSpecialCharacters(codepoint, COLOR_WHITE, colorMod))
if(processSpecialCharacters(codepoint, COLOR_WHITE))
{
continue;
}

View File

@@ -11,22 +11,27 @@
namespace
{
int menuID = 0;
// This is how much extra vertical space is needed for bounding/selection box
const int BOUNDING_EXTRA_HEIGHT = 32;
}
ui::menu::menu(int x, int y, int rectWidth, int fontSize, int maxScroll) :
m_X(x),
m_Y(y),
m_OriginalY(y),
m_FontSize(fontSize),
m_RectWidth(rectWidth),
m_RectHeight(m_FontSize + BOUNDING_EXTRA_HEIGHT),
m_Selected(0),
m_MaxScroll(maxScroll) { }
ui::menu::menu(int x, int y, int rectWidth, int fontSize, int maxScroll) : m_X(x),
m_Y(y),
m_OriginalY(y),
m_FontSize(fontSize),
m_RectWidth(rectWidth),
m_RectHeight(m_FontSize + BOUNDING_EXTRA_HEIGHT),
m_Selected(0),
m_MaxScroll(maxScroll)
{
// String for rendertarget
std::string menuTargetName = "menuTarget_" + std::to_string(menuID++);
// This is for rendering the options to. So text can't be rendered outside bounding box.
m_OptionRenderTarget = graphics::textureManager::createTexture(menuTargetName, m_RectWidth, m_RectHeight, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
}
ui::menu::menu(int x, int y, int rectWidth, int fontSize, int maxScroll, const std::string *menuOptions, int menuOptCount) :
menu(x, y, rectWidth, fontSize, maxScroll)
ui::menu::menu(int x, int y, int rectWidth, int fontSize, int maxScroll, const std::string *menuOptions, int menuOptCount) : menu(x, y, rectWidth, fontSize, maxScroll)
{
for (int i = 0; i < menuOptCount; i++)
{
@@ -53,6 +58,14 @@ void ui::menu::update(void)
{
m_Selected = 0;
}
else if (sys::input::buttonDown(HidNpadButton_AnyLeft) && (m_Selected -= m_MaxScroll) < 0)
{
m_Selected = 0;
}
else if (sys::input::buttonDown(HidNpadButton_AnyRight) && (m_Selected += m_MaxScroll) > menuSize)
{
m_Selected = menuSize;
}
// Calculate if scrolling needs to happen
if (m_Selected <= m_MaxScroll)
@@ -73,7 +86,7 @@ void ui::menu::update(void)
{
double addToY = static_cast<double>(static_cast<double>(m_TargetY) - static_cast<double>(m_Y)) / config::getAnimationScaling();
m_Y += std::ceil(addToY);
}
}
}
void ui::menu::render(SDL_Texture *target)
@@ -89,11 +102,17 @@ void ui::menu::render(SDL_Texture *target)
SDL_QueryTexture(target, NULL, NULL, NULL, &targetHeight);
for (int i = 0; i < (int)m_MenuOptions.size(); i++)
{
// Clear option target
graphics::textureClear(m_OptionRenderTarget.get(), COLOR_TRANSPARENT);
// Render option to it.
graphics::systemFont::renderText(m_MenuOptions.at(i), m_OptionRenderTarget.get(), 16, (m_RectHeight / 2) - (m_FontSize /2), m_FontSize, COLOR_WHITE);
// Render option target to target
graphics::textureRender(m_OptionRenderTarget.get(), target, m_X, m_Y + (i * m_RectHeight));
// If it's the selected option, render the selection box over top.
if (m_Selected == i)
{
ui::renderSelectionBox(target, m_X - 4, (m_Y + (i * m_RectHeight)) - 4, m_RectWidth, m_RectHeight, m_ColorMod);
ui::renderSelectionBox(target, m_X, (m_Y + (i * m_RectHeight)), m_RectWidth, m_RectHeight, m_ColorMod);
}
graphics::systemFont::renderText(m_MenuOptions.at(i), target, m_X + 8, m_Y + (i * m_RectHeight) + (m_RectHeight / 2 - m_FontSize / 2), m_FontSize, COLOR_WHITE);
}
}
@@ -104,7 +123,7 @@ void ui::menu::addOption(const std::string &newOption)
void ui::menu::updateColorPulse(void)
{
if (m_ColorShift && (m_ColorMod += 6) >= 0x72)
if (m_ColorShift && (m_ColorMod += 6) >= 0x72)
{
m_ColorShift = false;
}