mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-09-09 11:05:12 -05:00
Fixes, confirmation added
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "data/userSaveInfo.hpp"
|
||||
#include "data/titleInfo.hpp"
|
||||
#include <SDL2/SDL.h>
|
||||
#include "data/data.hpp"
|
||||
#include "filesystem/filesystem.hpp"
|
||||
#include "ui/slidePanel.hpp"
|
||||
#include "ui/menu.hpp"
|
||||
#include "appStates/appState.hpp"
|
||||
#include "system/task.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
class backupMenuState : public appState
|
||||
{
|
||||
@@ -33,10 +31,14 @@ class backupMenuState : public appState
|
||||
std::string m_OutputBasePath;
|
||||
// Slide in/out panel
|
||||
std::unique_ptr<ui::slidePanel> m_BackupPanel;
|
||||
// Width of panel/text
|
||||
int m_PanelWidth;
|
||||
// Folder listing
|
||||
std::unique_ptr<fs::directoryListing> m_BackupListing;
|
||||
// Listing to make sure there is a save
|
||||
std::unique_ptr<fs::directoryListing> m_SaveListing;
|
||||
// Folder menu
|
||||
std::unique_ptr<ui::menu> m_BackupMenu;
|
||||
// Render target for menu
|
||||
SDL_Texture *m_BackupMenuRenderTarget = NULL;
|
||||
};
|
||||
|
||||
32
inc/appStates/confirmState.hpp
Normal file
32
inc/appStates/confirmState.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "appStates/appState.hpp"
|
||||
#include "system/timer.hpp"
|
||||
#include "system/task.hpp"
|
||||
|
||||
class confirmState : public appState
|
||||
{
|
||||
public:
|
||||
// Message is the question asked. onConfirmation is the function executed if user confirms. Args is the shared_ptr sent to onConfirmation
|
||||
confirmState(const std::string &message, sys::taskFunction onConfirmation, std::shared_ptr<sys::taskArgs> args);
|
||||
~confirmState();
|
||||
|
||||
void update(void);
|
||||
void render(void);
|
||||
|
||||
private:
|
||||
// Message being displayed
|
||||
std::string m_Message;
|
||||
// Yes and no text
|
||||
std::string m_Yes;
|
||||
std::string m_No;
|
||||
// Timer for holding to confirm
|
||||
std::unique_ptr<sys::timer> m_HoldTimer;
|
||||
// Int for what stage for holding
|
||||
int8_t m_HoldStage = 0;
|
||||
// Function on confirm
|
||||
sys::taskFunction m_OnConfirmation;
|
||||
// Args to send m_OnConfirmation
|
||||
std::shared_ptr<sys::taskArgs> m_Args;
|
||||
};
|
||||
@@ -15,6 +15,8 @@ namespace fs
|
||||
int getListingCount(void) const;
|
||||
// Returns if item at index is a folder
|
||||
bool itemAtIsDirectory(const int &index) const;
|
||||
// Returns full path of item at index
|
||||
std::string getFullPathToItemAt(const int &index) const;
|
||||
// Returns full name + extension of index
|
||||
std::string getItemAt(const int &index) const;
|
||||
// Returns just the file name (no extension)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define COLOR_DIALOG_BOX 0x505050FF
|
||||
#define COLOR_WHITE 0xFFFFFFFF
|
||||
#define COLOR_BLACK 0x000000FF
|
||||
#define COLOR_DARK_GRAY 0xCACACAFF
|
||||
#define COLOR_SLIDE_PANEL_TARGET 0x000000AA
|
||||
#define COLOR_RED 0xFF0000FF
|
||||
#define COLOR_GREEN 0x00FF00FF
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace sys
|
||||
// Returns if button was pressed
|
||||
bool buttonDown(const HidNpadButton &button);
|
||||
bool buttonHeld(const HidNpadButton &button);
|
||||
bool buttonReleased(const HidNpadButton &button);
|
||||
|
||||
// Gets input and returns C++ string
|
||||
std::string getString(const std::string &defaultText, const std::string &headerText, const size_t &maximumLength);
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace sys
|
||||
public:
|
||||
// Inits timer with current ticks
|
||||
timer(const uint32_t &triggerTicks);
|
||||
// Restarts timer. Sets starting ticks to current
|
||||
void restartTimer(void);
|
||||
// Returns if triggerTicks has been reached.
|
||||
bool triggered(void);
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
// Thread status strings
|
||||
#define LANG_THREAD_CREATING_SAVE "threadStatusCreatingSaveData"
|
||||
#define LANG_THREAD_COPYING_FILE "threadStatusCopyingFile"
|
||||
#define LANG_THREAD_STATUS_DELETE "threadStatusDeletingFile"
|
||||
#define LANG_THREAD_DELETE_FILE "threadStatusDeletingFile"
|
||||
#define LANG_THREAD_OPENING_FOLDER "threadStatusOpeningFolder"
|
||||
#define LANG_THREAD_ADDING_TO_ZIP "threadStatusAddingFolderToZip"
|
||||
#define LANG_THREAD_DECOMPRESSING_FILE "threadStatusDecompressingFile"
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include "ui/lang.hpp"
|
||||
#include "ui/strings.hpp"
|
||||
#include "ui/menu.hpp"
|
||||
#include "ui/iconMenu.hpp"
|
||||
#include "ui/progressBar.hpp"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "system/input.hpp"
|
||||
#include "graphics/graphics.hpp"
|
||||
#include "appStates/backupMenuState.hpp"
|
||||
#include "appStates/confirmState.hpp"
|
||||
#include "appStates/taskState.hpp"
|
||||
#include "filesystem/filesystem.hpp"
|
||||
#include "system/task.hpp"
|
||||
@@ -24,9 +25,11 @@ struct backupArgs : sys::taskArgs
|
||||
};
|
||||
|
||||
// This is shared by overwrite and restore
|
||||
struct pathArg : sys::taskArgs
|
||||
struct pathArgs : sys::taskArgs
|
||||
{
|
||||
std::string source, destination;
|
||||
// For reloading folder list
|
||||
backupMenuState *sendingState = NULL;
|
||||
};
|
||||
|
||||
// These are the functions used for tasks
|
||||
@@ -105,7 +108,7 @@ void overwriteBackup(sys::task *task, std::shared_ptr<sys::taskArgs> args)
|
||||
|
||||
// Set status, cast args to type
|
||||
task->setThreadStatus("REPLACE THIS LATER");
|
||||
std::shared_ptr<pathArg> argIn = std::static_pointer_cast<pathArg>(args);
|
||||
std::shared_ptr<pathArgs> argIn = std::static_pointer_cast<pathArgs>(args);
|
||||
|
||||
// Get a test listing
|
||||
fs::directoryListing testListing(fs::DEFAULT_SAVE_MOUNT_DEVICE);
|
||||
@@ -143,7 +146,7 @@ void restoreBackup(sys::task *task, std::shared_ptr<sys::taskArgs> args)
|
||||
}
|
||||
|
||||
task->setThreadStatus("REPLACE THIS LATER");
|
||||
std::shared_ptr<pathArg> argIn = std::static_pointer_cast<pathArg>(args);
|
||||
std::shared_ptr<pathArgs> argIn = std::static_pointer_cast<pathArgs>(args);
|
||||
|
||||
// Test if there are actually files in the save
|
||||
fs::directoryListing testListing(argIn->source);
|
||||
@@ -154,6 +157,34 @@ void restoreBackup(sys::task *task, std::shared_ptr<sys::taskArgs> args)
|
||||
}
|
||||
}
|
||||
|
||||
void deleteBackup(sys::task *task, std::shared_ptr<sys::taskArgs> args)
|
||||
{
|
||||
if(args == nullptr)
|
||||
{
|
||||
task->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set thread status
|
||||
task->setThreadStatus(ui::strings::getString(LANG_THREAD_DELETE_FILE, 0));
|
||||
|
||||
// Cast args
|
||||
std::shared_ptr<pathArgs> argsIn = std::static_pointer_cast<pathArgs>(args);
|
||||
|
||||
if(std::filesystem::is_directory(argsIn->destination))
|
||||
{
|
||||
std::filesystem::remove_all(argsIn->destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::filesystem::remove(argsIn->destination);
|
||||
}
|
||||
|
||||
argsIn->sendingState->loadDirectoryList();
|
||||
|
||||
task->finished();
|
||||
}
|
||||
|
||||
backupMenuState::backupMenuState(data::user *currentUser, data::userSaveInfo *currentUserSaveInfo, data::titleInfo *currentTitleInfo) : m_CurrentUser(currentUser), m_CurrentUserSaveInfo(currentUserSaveInfo), m_CurrentTitleInfo(currentTitleInfo)
|
||||
{
|
||||
// This is the path used for all in/output. Create it if it doesn't exist.
|
||||
@@ -162,12 +193,14 @@ backupMenuState::backupMenuState(data::user *currentUser, data::userSaveInfo *cu
|
||||
|
||||
// Controls displayed at bottom
|
||||
m_BackupMenuControlGuide = ui::strings::getString(LANG_FOLDER_GUIDE, 0);
|
||||
int panelWidth = graphics::systemFont::getTextWidth(m_BackupMenuControlGuide, 18);
|
||||
m_PanelWidth = graphics::systemFont::getTextWidth(m_BackupMenuControlGuide, 18);
|
||||
|
||||
// The actual panel
|
||||
m_BackupPanel = std::make_unique<ui::slidePanel>("backupMenuPanel", panelWidth + 64, ui::slidePanelSide::PANEL_SIDE_RIGHT);
|
||||
m_BackupPanel = std::make_unique<ui::slidePanel>("backupMenuPanel", m_PanelWidth + 64, ui::slidePanelSide::PANEL_SIDE_RIGHT);
|
||||
// The menu of backups
|
||||
m_BackupMenu = std::make_unique<ui::menu>(10, 4, panelWidth + 44, 18, 7);
|
||||
m_BackupMenu = std::make_unique<ui::menu>(10, 4, m_PanelWidth + 44, 18, 6);
|
||||
// Render target that menu is rendered to
|
||||
m_BackupMenuRenderTarget = graphics::textureCreate("backupMenuRenderTarget", m_PanelWidth + 64, 647, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
|
||||
// Directory listing of backups
|
||||
m_BackupListing = std::make_unique<fs::directoryListing>(m_OutputBasePath);
|
||||
// Directory listing of save
|
||||
@@ -192,7 +225,7 @@ void backupMenuState::update(void)
|
||||
if (sys::input::buttonDown(HidNpadButton_A) && selected == 0)
|
||||
{
|
||||
// Check to make sure save data isn't empty before wasting time and space
|
||||
if (m_BackupListing->getListingCount() > 0)
|
||||
if (m_SaveListing->getListingCount() > 0)
|
||||
{
|
||||
// Data to send to task
|
||||
std::shared_ptr<backupArgs> backupTaskArgs = std::make_shared<backupArgs>();
|
||||
@@ -210,8 +243,53 @@ void backupMenuState::update(void)
|
||||
ui::popMessage::newMessage(ui::strings::getString(LANG_POP_SAVE_EMPTY, 0), ui::popMessage::POPMESSAGE_DEFAULT_TICKS);
|
||||
}
|
||||
}
|
||||
else if (sys::input::buttonDown(HidNpadButton_Y))
|
||||
else if(sys::input::buttonDown(HidNpadButton_A) && selected > 0)
|
||||
{
|
||||
// Selected item
|
||||
std::string selectedItem = m_BackupListing->getItemAt(selected - 1);
|
||||
// Get overwrite string
|
||||
std::string confirmOverwrite = stringUtil::getFormattedString(ui::strings::getCString(LANG_CONFIRM_OVERWRITE, 0), selectedItem.c_str());
|
||||
|
||||
// Arg pointer
|
||||
std::shared_ptr<pathArgs> paths = std::make_shared<pathArgs>();
|
||||
paths->destination = m_BackupListing->getFullPathToItemAt(selected - 1);
|
||||
|
||||
// Create confirmation
|
||||
std::unique_ptr<appState> overwriteConfirmationState = std::make_unique<confirmState>(confirmOverwrite, overwriteBackup, paths);
|
||||
// Push it real good
|
||||
jksv::pushNewState(overwriteConfirmationState);
|
||||
}
|
||||
else if (sys::input::buttonDown(HidNpadButton_Y) && selected > 0)
|
||||
{
|
||||
// Get selected menu item
|
||||
std::string selectedItem = m_BackupListing->getItemAt(selected - 1);
|
||||
// Get restoration string
|
||||
std::string confirmRestore = stringUtil::getFormattedString(ui::strings::getCString(LANG_CONFIRM_RESTORE, 0), selectedItem.c_str());
|
||||
|
||||
// Setup confirmation arg pointer
|
||||
std::shared_ptr<pathArgs> paths = std::make_shared<pathArgs>();
|
||||
paths->source = m_BackupListing->getFullPathToItemAt(selected - 1); // Need to subtract one to account for 'New' option
|
||||
|
||||
// Create confirmation
|
||||
std::unique_ptr<appState> restoreConfirmationState = std::make_unique<confirmState>(confirmRestore, restoreBackup, paths);
|
||||
// Push it to vector
|
||||
jksv::pushNewState(restoreConfirmationState);
|
||||
}
|
||||
else if(sys::input::buttonDown(HidNpadButton_X) && selected > 0)
|
||||
{
|
||||
// Get selected
|
||||
std::string selectedItem = m_BackupListing->getItemAt(selected - 1);
|
||||
// Get confirmation string
|
||||
std::string confirmDelete = stringUtil::getFormattedString(ui::strings::getCString(LANG_CONFIRM_DELETE, 0), selectedItem.c_str());
|
||||
|
||||
// Setup args
|
||||
std::shared_ptr<pathArgs> paths = std::make_shared<pathArgs>();
|
||||
paths->destination = m_BackupListing->getFullPathToItemAt(selected - 1);
|
||||
paths->sendingState = this;
|
||||
|
||||
// Create confirm and push
|
||||
std::unique_ptr<appState> deleteConfirmationState = std::make_unique<confirmState>(confirmDelete, deleteBackup, paths);
|
||||
jksv::pushNewState(deleteConfirmationState);
|
||||
}
|
||||
else if (sys::input::buttonDown(HidNpadButton_B))
|
||||
{
|
||||
@@ -225,11 +303,24 @@ void backupMenuState::update(void)
|
||||
|
||||
void backupMenuState::render(void)
|
||||
{
|
||||
// Get panel's render target and clear it first
|
||||
SDL_Texture *panelTarget = m_BackupPanel->getPanelRenderTarget();
|
||||
|
||||
graphics::textureClear(panelTarget, COLOR_SLIDE_PANEL_TARGET);
|
||||
m_BackupMenu->render(panelTarget);
|
||||
|
||||
// Clear menu render target
|
||||
graphics::textureClear(m_BackupMenuRenderTarget, COLOR_TRANSPARENT);
|
||||
|
||||
// Render menu to menu render target
|
||||
m_BackupMenu->render(m_BackupMenuRenderTarget);
|
||||
|
||||
// Render menu target to panel target (this is so the menu can only be draw so far and not cover guider)
|
||||
graphics::textureRender(m_BackupMenuRenderTarget, panelTarget, 0, 0);
|
||||
|
||||
// Draw divider and guide on bottom
|
||||
graphics::renderLine(panelTarget, 18, 648, m_PanelWidth + 54, 648, COLOR_WHITE);
|
||||
graphics::systemFont::renderText(m_BackupMenuControlGuide, panelTarget, 32, 673, 18, COLOR_WHITE);
|
||||
|
||||
// Render panel to framebuffer
|
||||
m_BackupPanel->render();
|
||||
}
|
||||
|
||||
|
||||
92
src/appStates/confirmState.cpp
Normal file
92
src/appStates/confirmState.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "appStates/confirmState.hpp"
|
||||
#include "appStates/taskState.hpp"
|
||||
#include "graphics/graphics.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
#include "system/input.hpp"
|
||||
#include "jksv.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
static const int HOLD_TICKS = 1000;
|
||||
|
||||
confirmState::confirmState(const std::string &message, sys::taskFunction onConfirmation, std::shared_ptr<sys::taskArgs> args) : m_Message(message), m_OnConfirmation(onConfirmation), m_Args(args)
|
||||
{
|
||||
// Init timer
|
||||
m_HoldTimer = std::make_unique<sys::timer>(HOLD_TICKS);
|
||||
// Get Text for yes and no
|
||||
m_Yes = ui::strings::getString(LANG_DIALOG_YES, 0);
|
||||
m_No = ui::strings::getString(LANG_DIALOG_NO, 0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_HoldTimer->restartTimer();
|
||||
}
|
||||
else if(sys::input::buttonHeld(HidNpadButton_A) && m_HoldStage < 3 && m_HoldTimer->triggered())
|
||||
{
|
||||
// Confirmed, create new task.
|
||||
if(++m_HoldStage == 3)
|
||||
{
|
||||
// Create new task
|
||||
std::unique_ptr<appState> confirmationTask = std::make_unique<taskState>(m_OnConfirmation, m_Args);
|
||||
jksv::pushNewState(confirmationTask);
|
||||
// Deactivate this one and pray JKSV catches it
|
||||
appState::deactivateState();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch and update yes accordingly
|
||||
switch (m_HoldStage)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Yes = ui::strings::getString(LANG_HOLDING_TEXT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
m_Yes = ui::strings::getString(LANG_HOLDING_TEXT, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
m_Yes = ui::strings::getString(LANG_HOLDING_TEXT, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sys::input::buttonReleased(HidNpadButton_A))
|
||||
{
|
||||
m_Yes = ui::strings::getString(LANG_DIALOG_YES, 0);
|
||||
}
|
||||
else if(sys::input::buttonDown(HidNpadButton_B))
|
||||
{
|
||||
// Party's over. Just stop
|
||||
appState::deactivateState();
|
||||
}
|
||||
}
|
||||
|
||||
void confirmState::render(void)
|
||||
{
|
||||
// Darken underlying
|
||||
graphics::renderRect(NULL, 0, 0, 1280, 720, COLOR_DIM_BACKGROUND);
|
||||
|
||||
// Calculate X position of m_Yes because it changes on hold
|
||||
int yesXPosition = 458 - (graphics::systemFont::getTextWidth(m_Yes, 18) / 2);
|
||||
|
||||
// Render dialog box
|
||||
ui::renderDialogBox(NULL, 280, 262, 720, 256);
|
||||
graphics::systemFont::renderTextWrap(m_Message, NULL, 312, 288, 18, 656, COLOR_WHITE);
|
||||
graphics::renderLine(NULL, 280, 454, 999, 454, COLOR_DARK_GRAY);
|
||||
graphics::renderLine(NULL, 640, 454, 640, 517, COLOR_DARK_GRAY);
|
||||
graphics::systemFont::renderText(m_Yes, NULL, yesXPosition, 478, 18, COLOR_WHITE);
|
||||
graphics::systemFont::renderText(m_No, NULL, 782, 478, 18, COLOR_WHITE);
|
||||
}
|
||||
@@ -30,6 +30,11 @@ bool fs::directoryListing::itemAtIsDirectory(const int &index) const
|
||||
return std::filesystem::is_directory(m_DirectoryList.at(index));
|
||||
}
|
||||
|
||||
std::string fs::directoryListing::getFullPathToItemAt(const int &index) const
|
||||
{
|
||||
return m_DirectoryList.at(index);
|
||||
}
|
||||
|
||||
std::string fs::directoryListing::getItemAt(const int &index) const
|
||||
{
|
||||
size_t lastSlash = m_DirectoryList.at(index).find_last_of('/') + 1;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <array>
|
||||
#include "filesystem/fileParser.hpp"
|
||||
#include "stringUtil.hpp"
|
||||
#include "log.hpp"
|
||||
@@ -8,6 +9,8 @@
|
||||
#define VALUE_TRUE "true"
|
||||
#define VALUE_FALSE "false"
|
||||
|
||||
static const int FILE_PARSER_LINE_SIZE_LIMIT = 0x1000;
|
||||
|
||||
fs::fileParser::fileParser(const std::string &filePath)
|
||||
{
|
||||
m_File = std::fopen(filePath.c_str(), "r");
|
||||
@@ -25,30 +28,41 @@ bool fs::fileParser::isOpen(void) const
|
||||
|
||||
bool fs::fileParser::readLine(void)
|
||||
{
|
||||
// To return whether a new line was successfully read
|
||||
bool lineRead = false;
|
||||
char lineBuffer[0x1000];
|
||||
while(std::fgets(lineBuffer, 0x1000, m_File))
|
||||
// Buffer to read lines into
|
||||
std::array<char, FILE_PARSER_LINE_SIZE_LIMIT> lineBuffer;
|
||||
|
||||
// Loop until a line isn't a comment or new line
|
||||
while(std::fgets(lineBuffer.data(), FILENAME_MAX, m_File))
|
||||
{
|
||||
char lineStart = lineBuffer[0];
|
||||
// Get first char in line. If it's a comment or new line, continue loop
|
||||
char lineStart = lineBuffer.at(0);
|
||||
if(lineStart == '#' || lineStart == '\n' || lineStart == '\r')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CurrentLine.assign(lineBuffer);
|
||||
// Assign lineBuffer to current line C++ string
|
||||
m_CurrentLine.assign(lineBuffer.data());
|
||||
// Line read was successful, break the loop
|
||||
lineRead = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// These need to be removed because they can cause issues
|
||||
stringUtil::eraseCharacterFromString('\n', m_CurrentLine);
|
||||
stringUtil::eraseCharacterFromString('\r', m_CurrentLine);
|
||||
|
||||
// Find first "word" of line.
|
||||
m_CurrentLinePosition = m_CurrentLine.find_first_of(VALUE_DELIMINATORS);
|
||||
// Assign it
|
||||
m_ItemName.assign(m_CurrentLine.begin(), m_CurrentLine.begin() + m_CurrentLinePosition);
|
||||
// Remove spaces
|
||||
stringUtil::eraseCharacterFromString(' ', m_ItemName);
|
||||
|
||||
// Increment after value deliminator
|
||||
++m_CurrentLinePosition;
|
||||
|
||||
return lineRead;
|
||||
@@ -59,6 +73,7 @@ std::string fs::fileParser::getCurrentItemName(void) const
|
||||
return m_ItemName;
|
||||
}
|
||||
|
||||
// All of these just us getNextValueAsString and converts on return
|
||||
bool fs::fileParser::getNextValueAsBool(void)
|
||||
{
|
||||
std::string value = getNextValueAsString();
|
||||
@@ -89,10 +104,14 @@ uint64_t fs::fileParser::getNextValueAsUint64(void)
|
||||
|
||||
std::string fs::fileParser::getNextValueAsString(void)
|
||||
{
|
||||
// Find the first char that isn't a space or comma
|
||||
m_CurrentLinePosition = m_CurrentLine.find_first_not_of(" ,", m_CurrentLinePosition);
|
||||
// Starting position of string we're extracting
|
||||
size_t startingPosition = m_CurrentLinePosition;
|
||||
|
||||
// Need to test for quotes
|
||||
char firstChar = m_CurrentLine.at(m_CurrentLinePosition);
|
||||
// If it's a quote, just keep going until the ending quote.
|
||||
if(firstChar == '"')
|
||||
{
|
||||
m_CurrentLinePosition = m_CurrentLine.find_first_of('"', ++startingPosition);
|
||||
@@ -101,5 +120,6 @@ std::string fs::fileParser::getNextValueAsString(void)
|
||||
{
|
||||
m_CurrentLinePosition = m_CurrentLine.find_first_of(STRING_DELIMINATORS);
|
||||
}
|
||||
// Return the substring
|
||||
return m_CurrentLine.substr(startingPosition, m_CurrentLinePosition++ - startingPosition);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
@@ -11,6 +12,8 @@
|
||||
#include "graphics/systemFont.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
static const int WORD_WRAP_BUFFER_LENGTH = 0x1000;
|
||||
|
||||
//Masks for converting to surface
|
||||
static const uint32_t s_RedMask = 0xFF000000;
|
||||
static const uint32_t s_GreenMask = 0x00FF0000;
|
||||
@@ -226,6 +229,7 @@ void graphics::systemFont::exit(void)
|
||||
FT_Done_Face(s_FTFaces[i]);
|
||||
}
|
||||
FT_Done_FreeType(s_FTLib);
|
||||
|
||||
logger::log("systemFont::exit(): Succeeded.");
|
||||
}
|
||||
|
||||
@@ -265,6 +269,7 @@ void graphics::systemFont::renderText(const std::string &text, SDL_Texture *targ
|
||||
}
|
||||
else if(codepoint == '\n')
|
||||
{
|
||||
// Break line, reset X, increase Y
|
||||
workingX = x;
|
||||
workingY += fontSize + 8;
|
||||
continue;
|
||||
@@ -273,8 +278,11 @@ void graphics::systemFont::renderText(const std::string &text, SDL_Texture *targ
|
||||
glyphData *gd = getGlyph(codepoint, fontSize);
|
||||
if(gd)
|
||||
{
|
||||
// Set color just to be sure
|
||||
SDL_SetTextureColorMod(gd->glyph, getRed(workingColor), getGreen(workingColor), getBlue(workingColor));
|
||||
// Render glyph texture
|
||||
graphics::textureRender(gd->glyph, target, workingX + gd->left, workingY + (fontSize - gd->top));
|
||||
// X update
|
||||
workingX += gd->advanceX;
|
||||
}
|
||||
}
|
||||
@@ -287,7 +295,7 @@ void graphics::systemFont::renderTextWrap(const std::string &text, SDL_Texture *
|
||||
int workingY = y;
|
||||
int stringLength = text.length();
|
||||
// This buffer is used to calculate if the next word should create a line break
|
||||
char wordBuffer[0x100];
|
||||
std::array<char, WORD_WRAP_BUFFER_LENGTH> wordBuffer = { 0 };
|
||||
|
||||
resizeFont(fontSize);
|
||||
|
||||
@@ -296,21 +304,24 @@ void graphics::systemFont::renderTextWrap(const std::string &text, SDL_Texture *
|
||||
// Find the next char we can break a line at
|
||||
size_t nextBreakpoint = findNextBreakPoint(&text.c_str()[i]);
|
||||
|
||||
// Clear and copy string up until that point to wordBuffer
|
||||
std::memset(wordBuffer, 0x00, 0x100);
|
||||
std::memcpy(wordBuffer, &text.c_str()[i], nextBreakpoint);
|
||||
// Copy string up until that point to wordBuffer
|
||||
std::snprintf(wordBuffer.data(), WORD_WRAP_BUFFER_LENGTH, "%s", text.substr(i, nextBreakpoint).c_str());
|
||||
|
||||
// Go to next line if maxWidth is exceeded
|
||||
int wordWidth = graphics::systemFont::getTextWidth(wordBuffer, fontSize);
|
||||
int wordWidth = graphics::systemFont::getTextWidth(wordBuffer.data(), fontSize);
|
||||
if(workingX + wordWidth >= x + maxWidth)
|
||||
{
|
||||
workingX = x;
|
||||
workingY += fontSize + 8;
|
||||
}
|
||||
// Render word
|
||||
graphics::systemFont::renderText(wordBuffer, target, workingX, workingY, fontSize, color);
|
||||
graphics::systemFont::renderText(wordBuffer.data(), target, workingX, workingY, fontSize, color);
|
||||
|
||||
// Increase workingX by word width
|
||||
workingX += wordWidth;
|
||||
|
||||
// Add length to i
|
||||
i += std::strlen(wordBuffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
src/log.cpp
16
src/log.cpp
@@ -1,7 +1,10 @@
|
||||
#include <array>
|
||||
#include <cstdarg>
|
||||
#include <mutex>
|
||||
#include "log.hpp"
|
||||
|
||||
static const int LOG_VA_BUFFER_SIZE = 0x1000;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::ofstream s_LogFile;
|
||||
@@ -15,14 +18,17 @@ void logger::init(void)
|
||||
|
||||
void logger::log(const char *format, ...)
|
||||
{
|
||||
char vaBuffer[0x800];
|
||||
va_list args;
|
||||
// Buffer for va
|
||||
std::array<char, LOG_VA_BUFFER_SIZE> vaBuffer;
|
||||
|
||||
// VA
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(vaBuffer, 0x800, format, args);
|
||||
vsnprintf(vaBuffer.data(), LOG_VA_BUFFER_SIZE, format, args);
|
||||
va_end(args);
|
||||
|
||||
// JIC because of task threads
|
||||
// This is because of threading
|
||||
s_LogMutex.lock();
|
||||
s_LogFile << vaBuffer << std::endl; // Using std::endl for flush for more reliable logging
|
||||
s_LogFile << vaBuffer.data() << std::endl; // endl for buffer flushing
|
||||
s_LogMutex.unlock();
|
||||
}
|
||||
@@ -30,6 +30,11 @@ bool sys::input::buttonHeld(const HidNpadButton &button)
|
||||
return padGetButtons(&s_PadState) & button;
|
||||
}
|
||||
|
||||
bool sys::input::buttonReleased(const HidNpadButton &button)
|
||||
{
|
||||
return padGetButtonsUp(&s_PadState) & button;
|
||||
}
|
||||
|
||||
std::string sys::input::getString(const std::string &defaultText, const std::string &headerText, const size_t &maximumLength)
|
||||
{
|
||||
// Keyboard config
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
|
||||
sys::timer::timer(const uint32_t &triggerTicks) : m_TriggerTicks(triggerTicks)
|
||||
{
|
||||
// Save starting ticks
|
||||
restartTimer();
|
||||
}
|
||||
|
||||
void sys::timer::restartTimer(void)
|
||||
{
|
||||
// Set starting ticks
|
||||
m_StartingTicks = SDL_GetTicks();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "ui/lang.hpp"
|
||||
#include "ui/strings.hpp"
|
||||
#include "log.hpp"
|
||||
#include "stringUtil.hpp"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ui/ui.hpp"
|
||||
#include "ui/lang.hpp"
|
||||
#include "graphics/graphics.hpp"
|
||||
|
||||
namespace
|
||||
|
||||
Reference in New Issue
Block a user