Fixes, confirmation added

This commit is contained in:
Your Name
2024-05-28 14:19:56 -04:00
parent 8f30cada67
commit 9cf236d7fe
18 changed files with 310 additions and 36 deletions

View File

@@ -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;
};

View 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;
};

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"

View File

@@ -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"

View File

@@ -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();
}

View 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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -1,6 +1,6 @@
#include <map>
#include <string>
#include "ui/lang.hpp"
#include "ui/strings.hpp"
#include "log.hpp"
#include "stringUtil.hpp"

View File

@@ -1,5 +1,4 @@
#include "ui/ui.hpp"
#include "ui/lang.hpp"
#include "graphics/graphics.hpp"
namespace