WIP UI Update

This commit is contained in:
J-D-K
2021-07-09 23:05:19 -04:00
parent 3e89939308
commit 6fdd7d33e7
34 changed files with 2091 additions and 2225 deletions

View File

@@ -38,7 +38,7 @@ INCLUDES := inc
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 06.14.2021
APP_VERSION := 07.09.2021
ROMFS := romfs
ICON := icon.jpg

View File

@@ -70,40 +70,17 @@ JKSV on Switch started as a small project/port to test some things and get famil
* Rescan Titles reloads save data information. This can be used to reload after a process is terminated or when options are changed.
* Mount Process RomFS opens the title's romfs that is taken over to launch the homebrew menu. This only works as an NRO. The NSP will only open JKSV's own RomFS.
* Backup JKSV folder writes the entire JKSV folder to a ZIP archive and places it in your JKSV folder.
6. Options
* Include Dev Sv will add Device Save games such as Animal Crossing to your user account saves for easier access.
* AutoBackup will create a backup of your current save before restoring just in case.
* Overclock will clock your Switch's CPU to 1224MHz on boot.
* Hold to [X] will disable needing to hold down A to confirm an action
* Force Mount will only allow JKSV to list titles it can open. Disabling will give a complete list of all saves on your system
* Account Sys. Saves will allow you to see and open system saves associated with user accounts
* Write to Sys. Saves will allow you to write data to system save archives. This can be dangerous.
* Text UI mode enables a simplified UI that only uses text menus
* Direct FS Commands uses a simple wrapper instead of libnx's stdio.
* Skip User Select jumps directly to the first user found instead of requiring a user to be selected.
* Export to ZIP uses minizip to compress your save data to a ZIP archive instead of a folder full of files. This saves space and makes moving saves more convienient.
* Sort changes the way titles are sorted. Alphabetically, Most time played, or by last title played.
**IMPORTANT**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place.
**NOTE**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place.
## Building:
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
2. Requires switch-
* freetype
* libpng
* zlib
* libjpeg-turbo
* curl
* libjson-c
* sdl2
* sdl2_image
* libwebp
2. Requires switch-freetype, libpng, zlib, libjpeg-turbo, lib-curl, and lib-json-c
## Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8
* Authors of switch-examples for account and save mounting code.
* [Iguniisu](https://github.com/igniscitrinus) for the icon.
* Uses graphics from [Twemoji](https://github.com/twitter/twemoji) covered by the [Creative Commons License](https://creativecommons.org/licenses/by/4.0/legalcode)
* [Leo](https://github.com/qazrfv1234) For the Traditional Chinese translation
* [JamePeng](https://github.com/JamePeng) For the Simplified Chinese translation.

View File

@@ -1,6 +1,4 @@
#ifndef DATA_H
#define DATA_H
#pragma once
#include <switch.h>
#include <vector>
@@ -10,14 +8,16 @@
#include "gfx.h"
#define curUser users[data::selUser]
#define curData users[data::selUser].titles[data::selData]
#define curData users[data::selUser].titleInfo[data::selData]
#define BLD_MON 06
#define BLD_DAY 14
#define BLD_MON 7
#define BLD_DAY 9
#define BLD_YEAR 2021
namespace data
{
extern bool forceMount;
//Loads user + title info
void init();
void exit();
@@ -29,61 +29,27 @@ namespace data
void loadFav();
void saveFav();
void loadDefs();
void exportIcons();
//Draws some stats to the upper left corner
void dispStats();
//Class to store title info
class titledata
//Global stuff for all titles/saves
typedef struct
{
public:
titledata() = default;
//Attempts to read title's info
titledata(const FsSaveDataInfo& inf, NsApplicationControlData *dat);
NacpStruct nacp;
std::string title, safeTitle, author;//Shortcuts sorta.
SDL_Texture *icon;
bool fav;
} titleInfo;
//Returns title + title without forbidden chars
std::string getTitle() const { return title;}
std::string getTitleSafe() const { return titleSafe; }
std::string getAuthor() const { return author; }
//Creates title folder
void createDir() const;
//Returns folder path
std::string getPath() const;
//returns save_data_id string. only used for helping identify nand files
std::string getTIDStr() const;
std::string getSaveIDStr() const;
uint64_t getID() const { return id; }
uint64_t getSaveID() const { return saveID; }
uint16_t getSaveIndex() const { return saveIndex; }
FsSaveDataType getType() const { return (FsSaveDataType)saveDataType; }
void setID(const uint64_t& _id){ id = _id; }
void setIndex(const uint16_t& _ind){ saveIndex = _ind; }
void setType(FsSaveDataType type) { saveDataType = type; }
void setFav(bool setFav) { favorite = setFav; }
bool getFav() const { return favorite; }
void assignIcon();
void drawIcon(bool full, unsigned x, unsigned y);
void drawIconFav(bool full, unsigned x, unsigned y);
void setPlayTime(const uint32_t& _p){ playMins = _p; }
uint32_t getPlayTime() const { return playMins; }
void setLastTimeStamp(const uint32_t& _ts){ lastTimeStamp = _ts; }
uint32_t getLastTimeStamp() const { return lastTimeStamp; }
void setLaunchCount(const uint32_t& _lc) { launchCount = _lc; }
uint32_t getLaunchCount() const { return launchCount; }
private:
SDL_Texture *icon;
uint8_t saveDataType;
std::string title, titleSafe, author;
uint64_t id, saveID;
uint16_t saveIndex;
uint32_t playMins, lastTimeStamp, launchCount;
bool favorite = false;
};
//Holds stuff specific to user's titles/saves
typedef struct
{
//Makes it easier to grab id
uint64_t saveID;
FsSaveDataInfo saveInfo;
PdmPlayStatistics playStats;
} userTitleInfo;
//Class to store user info + titles
class user
@@ -107,13 +73,11 @@ namespace data
std::string getUsername() const { return username; }
std::string getUsernameSafe() const { return userSafe; }
//Vector for storing save data info for user
std::vector<titledata> titles;
void loadPlayTimes();
SDL_Texture *getUserIcon(){ return userIcon; }
void delIcon(){ SDL_DestroyTexture(userIcon); }
void drawIcon(int x, int y) { gfx::texDraw(userIcon, x, y); }
void drawIconHalf(int x, int y) { gfx::texDrawStretch(userIcon, x, y, 128, 128); }
void delIcon() { SDL_DestroyTexture(userIcon); }
std::vector<data::userTitleInfo> titleInfo;
void addUserTitleInfo(const uint64_t& _tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats);
private:
AccountUid userID;
@@ -123,17 +87,34 @@ namespace data
SDL_Texture *userIcon;
};
//Gets total count of save containers
unsigned getTotalSaves();
//Adds title to blacklist
void blacklistAdd(data::titledata& t);
void blacklistAdd(const uint64_t& tid);
//Adds title to favorite list
void favoriteTitle(data::titledata& t);
void favoriteTitle(const uint64_t& tid);
bool isFavorite(const uint64_t& tid);
//User vector
extern std::vector<user> users;
extern std::unordered_map<uint64_t, SDL_Texture *> icons;
//Title data/info map
extern std::unordered_map<uint64_t, data::titleInfo> titles;
//Gets pointer to info
data::titleInfo *getTitleInfoByTID(const uint64_t& tid);
//More shortcut functions
std::string getTitleNameByTID(const uint64_t& tid);
std::string getTitleSafeNameByTID(const uint64_t& tid);
SDL_Texture *getTitleIconByTID(const uint64_t& tid);
inline int getTitleIndexInUser(const data::user& u, const uint64_t& sid)
{
for(unsigned i = 0; i < u.titleInfo.size(); i++)
{
if(u.titleInfo[i].saveID == sid)
return i;
}
return -1;
}
//Options and info
//Restores config to default
@@ -143,5 +124,3 @@ namespace data
extern bool incDev, autoBack, ovrClk, holdDel, holdRest, holdOver, forceMount, accSysSave, sysSaveWrite, directFsCmd, skipUser, zip, langOverride;
extern uint8_t sortType;
}
#endif // DATA_H

View File

@@ -1,5 +1,4 @@
#ifndef FILE_H
#define FILE_H
#pragma once
#include <string>
#include <cstdio>
@@ -11,6 +10,7 @@
#include "fsfile.h"
#include "data.h"
#include "miscui.h"
namespace fs
{
@@ -18,7 +18,7 @@ namespace fs
void exit();
//Mounts usr's save data for open. Returns false it fails
bool mountSave(const data::user& usr, const data::titledata& open);
bool mountSave(const FsSaveDataInfo& _m);
inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; }
void copyFile(const std::string& from, const std::string& to);
@@ -127,9 +127,19 @@ namespace fs
bool opened = false;
};
typedef struct
{
ui::menu *m;
fs::dirList *d;
} backupArgs;
//Take a pointer to backupArgs^
void createNewBackup(void *a);
void overwriteBackup(void *a);
void restoreBackup(void *a);
void deleteBackup(void *a);
void logOpen();
void logWrite(const char *fmt, ...);
void logClose();
}
#endif // FILE_H

9
inc/fld.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
namespace ui
{
void fldInit();
void fldExit();
void fldUpdate();
void fldDraw();
}

View File

@@ -1,5 +1,4 @@
#ifndef FSFILE_H
#define FSFILE_H
#pragma once
#include <switch.h>
#include <stdint.h>
@@ -97,5 +96,3 @@ inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); }
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,5 +1,4 @@
#ifndef GFX_H
#define GFX_H
#pragma once
#include <SDL.h>
@@ -9,51 +8,67 @@ namespace gfx
void init();
void exit();
void clear(const SDL_Color *c);
void present();
SDL_Texture *loadJPEGMem(const void *jpegData, size_t jpegSize);
SDL_Texture *loadImageFile(const char *file);
void drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...);
void drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...);
void drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...);
void drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...);
size_t getTextWidth(const char *str, int fontSize);
//Shortcuts for drawing
inline void texDraw(SDL_Texture *tex, int x, int y)
inline void texDraw(SDL_Texture *target, SDL_Texture *tex, int x, int y)
{
int tW = 0, tH = 0;
if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0)
{
SDL_SetRenderTarget(gfx::render, target);
SDL_Rect src = {0, 0, tW, tH};
SDL_Rect pos = {x, y, tW, tH};
SDL_RenderCopy(render, tex, &src, &pos);
SDL_RenderCopy(gfx::render, tex, &src, &pos);
}
}
inline void texDrawStretch(SDL_Texture *tex, int x, int y, int w, int h)
inline void texDrawStretch(SDL_Texture *target, SDL_Texture *tex, int x, int y, int w, int h)
{
int tW = 0, tH = 0;
if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0)
{
SDL_SetRenderTarget(gfx::render, target);
SDL_Rect src = {0, 0, tW, tH};
SDL_Rect pos = {x, y, w, h};
SDL_RenderCopy(render, tex, &src, &pos);
SDL_RenderCopy(gfx::render, tex, &src, &pos);
}
}
inline void drawLine(const SDL_Color *c, int x1, int y1, int x2, int y2)
inline void texDrawPart(SDL_Texture *target, SDL_Texture *tex, int srcX, int srcY, int srcW, int srcH, int dstX, int dstY)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_RenderDrawLine(render, x1, y1, x2, y2);
SDL_Rect src = {srcX, srcY, srcW, srcH};
SDL_Rect dst = {dstX, dstY, srcW, srcH};
SDL_SetRenderTarget(gfx::render, target);
SDL_RenderCopy(gfx::render, tex, &src, &dst);
}
inline void drawRect(const SDL_Color *c, int x, int y, int w, int h)
inline void drawLine(SDL_Texture *target, const SDL_Color *c, int x1, int y1, int x2, int y2)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_SetRenderTarget(gfx::render, target);
SDL_SetRenderDrawColor(gfx::render, c->r, c->g, c->b, c->a);
SDL_RenderDrawLine(gfx::render, x1, y1, x2, y2);
}
inline void drawRect(SDL_Texture *target, const SDL_Color *c, int x, int y, int w, int h)
{
SDL_SetRenderTarget(gfx::render, target);
SDL_SetRenderDrawColor(gfx::render, c->r, c->g, c->b, c->a);
SDL_Rect rect = {x, y, w, h};
SDL_RenderFillRect(render, &rect);
SDL_RenderFillRect(gfx::render, &rect);
}
inline void clearTarget(SDL_Texture *target, const SDL_Color *clear)
{
SDL_SetRenderTarget(gfx::render, target);
SDL_SetRenderDrawColor(gfx::render, clear->r, clear->g, clear->b, clear->a);
SDL_RenderClear(gfx::render);
}
}
#endif // GFX_H

View File

@@ -1,54 +0,0 @@
#ifndef MENU_H
#define MENU_H
#include <string>
#include <vector>
#include "gfx.h"
#include "miscui.h"
namespace ui
{
class menu
{
public:
void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW);
//Adds option
void addOpt(const std::string& add);
//Changes opt text
void editOpt(int ind, const std::string& ch);
//Clears menu stuff
~menu();
//Handles controller input
void handleInput(const uint64_t& down, const uint64_t& held);
//Returns selected option
int getSelected() { return selected; }
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void draw(const SDL_Color *textClr);
//Clears and resets menu
void reset();
//Resets selected + start
void resetSel() { selected = 0; start = 0; }
//Adjusts things after changes are made
void adjust();
private:
//drawing x and y + rectangle width
unsigned x = 0, y = 0, rW = 0, rY = 0;
//Options vector
std::vector<std::string> opt;
//Selected + frame counting for auto-scroll
int selected = 0, fc = 0, start = 0;
//How much we shift the color of the rectangle
uint8_t clrSh = 0;
bool clrAdd = true;
};
}
#endif

View File

@@ -1,39 +1,139 @@
#ifndef MISCUI_H
#define MISCUI_H
#pragma once
#include <SDL.h>
#include "type.h"
#include "gfx.h"
#define PROG_MAX_WIDTH_DEFAULT 576
#define POP_FRAME_DEFAULT 130
#define MENU_FONT_SIZE_DEFAULT 18
#define MENU_MAX_SCROLL_DEFAULT 15
typedef enum
{
FUNC_A,
FUNC_B,
FUNC_X,
FUNC_Y,
} funcBtn;
typedef enum
{
MENU_X,
MENU_Y,
MENU_RECT_WIDTH,
MENU_FONT_SIZE,
MENU_MAX_SCROLL
} menuParams;
//For smaller classes that aren't easy to get lost in and general functions
namespace ui
{
typedef struct
{
SDL_Texture *icn = NULL;
std::string txt;
funcPtr func[4] = {NULL};
void *argPtr[4] = {NULL};
} menuOpt;
class menu
{
public:
menu() = default;
//X, Y, Rect width/Max length, Font size, max to show
void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW, const unsigned& _fS, const unsigned& _mL);
void editParam(int _param, unsigned newVal);
//Gets executed when menu changes at all
void setOnChangeFunc(funcPtr func){ onChange = func; }
//executed when .update() is called.
void setCallback(funcPtr _callback, void *args) { callback = _callback; callbackArgs = args; }
//Adds option.
void addOpt(SDL_Texture *_icn, const std::string& add);
//Changes opt text
void editOpt(int ind, SDL_Texture *_icn, const std::string& ch);
void setOptFunc(unsigned _ind, unsigned _funcbtn, funcPtr _func, void *args);
void updateOptArgs(unsigned _ind, unsigned _funcbtn, void *args){ opt[_ind].argPtr[_funcbtn] = args; }
int getOptPos(const std::string& txt);
//Clears menu stuff
~menu();
//Handles controller input and executes functions for buttons if they're set
void update();
//Returns selected option
int getSelected() { return selected; }
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText);
//Clears and resets menu
void reset();
//Resets selected + start
void resetSel() { selected = 0; start = 0; }
//Enables control/disables drawing select box
void setActive(bool _set);
bool getActive() { return isActive; }
private:
//drawing x and y + rectangle width/height. Height is calc'd with font size
int x = 0, y = 0, rW = 0, rY = 0, fSize = 0, rH = 0, mL = 0;
//Options vector
std::vector<ui::menuOpt> opt;
//Selected + frame counting for auto-scroll
int selected = 0, fc = 0, start = 0;
//How much we shift the color of the rectangle
uint8_t clrSh = 0;
bool clrAdd = true, isActive = true;
funcPtr onChange = NULL, callback = NULL;
void *callbackArgs, *funcArgs;
};
//Progress bar for showing loading. Mostly so people know it didn't freeze
class progBar
{
public:
progBar() = default;
//Constructor. _max is the maximum value
progBar(const uint64_t& _max, const uint64_t& _maxWidth) { max = _max; maxWidth = _maxWidth; }
void setMax(const uint64_t& _max, const uint64_t& _maxWidth){ max = _max; maxWidth = _maxWidth; }
progBar(const uint64_t& _max) { max = _max; }
//Updates progress
void update(const uint64_t& _prog);
void incProgress(unsigned inc){ prog += inc; }
//Draws with text at top
void draw(const std::string& text, const std::string& head);
//Draws without dialog box
void drawNoDialog(int x, int y);
private:
uint64_t max, prog;
float width;
};
//_draw is called and passed the panel texture/target when this.draw() is called.
class slideOutPanel
{
public:
slideOutPanel(int _w, int _h, int _y, funcPtr _draw);
~slideOutPanel();
void openPanel() { open = true; }
void closePanel() { open = false; }
bool isOpen() { return open; }
void draw(const SDL_Color *backCol);
private:
uint64_t max, prog, maxWidth;
float width;
int w, h, x = 1280, y, slideSpd = 0;
bool open = false;
SDL_Texture *panel;
funcPtr drawFunc;
};
//General use
@@ -41,11 +141,10 @@ namespace ui
bool confirm(bool hold, const char *fmt, ...);
bool confirmTransfer(const std::string& f, const std::string& t);
bool confirmDelete(const std::string& p);
void drawTextbox(int x, int y, int w, int h);
void drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh);
void drawTextbox(SDL_Texture *target, int x, int y, int w, int h);
//Popup from freebird
void showPopup(unsigned frames, const char *fmt, ...);
void drawPopup(const uint64_t& down);
}
#endif // MISCUI_H

13
inc/ttl.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
namespace ui
{
void ttlInit();
void ttlExit();
//JIC for func ptr
void setupTiles(void *);
void ttlReset();
void ttlUpdate();
void ttlDraw(SDL_Texture *target);
}

View File

@@ -1,31 +0,0 @@
#ifndef TXTUI_H
#define TXTUI_H
#include "data.h"
namespace ui
{
void textUserPrep();
void textTitlePrep(data::user& u);
void textUserMenuUpdate(const uint64_t& down, const uint64_t& held);
void drawTextUserMenu();
void textTitleMenuUpdate(const uint64_t& down, const uint64_t& held);
void drawTextTitleMenu();
void textFolderMenuUpdate(const uint64_t& down, const uint64_t& held);
void drawTextFolderMenu();
void updateExMenu(const uint64_t& down, const uint64_t& held);
void drawExMenu();
void exMenuPrep();
//Options
void optMenuInit();
void updateOptMenu(const uint64_t& down, const uint64_t& held);
void drawOptMenu();
}
#endif

4
inc/type.h Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
//Misc stuff for new menu code
typedef void (*funcPtr)(void *);

View File

@@ -1,19 +1,18 @@
#ifndef UI_H
#define UI_H
#pragma once
#include <switch.h>
#include <vector>
#include <string>
#include "data.h"
#include "uistr.h"
#include "gfx.h"
//ui headers - split up to keep a bit more organized
#include "menu.h"
#include "miscui.h"
#include "txtui.h"
#include "uiupdate.h"
#include "uistr.h"
#include "usr.h"
#include "ttl.h"
#include "fld.h"
enum menuState
{
@@ -38,10 +37,12 @@ namespace ui
//pad data cause i don't know where else to put it
extern PadState pad;
static inline void updatePad() { padUpdate(&pad); }
extern HidTouchScreenState touchState;
static inline void updateInput() { touchState = {0}; padUpdate(&pad); hidGetTouchScreenStates(&touchState, 1); }
inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); }
inline uint64_t padKeysHeld() { return padGetButtons(&pad); }
inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); }
inline void touchGetXY(uint32_t *x, uint32_t *y) { *x = touchState.touches[0].x; *y = touchState.touches[0].y; }
inline void changeState(int newState)
{
@@ -52,7 +53,7 @@ namespace ui
//Holds theme set id
extern ColorSetId thmID;
//Both UI modes need access to thi
//Both UI modes need access to this
extern std::string folderMenuInfo;
/*Colors
@@ -60,10 +61,13 @@ namespace ui
txtCont = text that contrasts clearClr
txtDiag = text color for dialogs
*/
extern SDL_Color clearClr, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect;
extern SDL_Color clearClr, transparent, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect, divClr, heartColor, slidePanelColor;
//Textbox graphics
extern SDL_Texture *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight;
//Menu bounding
extern SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
//Covers left and right of progress bar to fake being not a rectangle.
extern SDL_Texture *progCovLeft, *progCovRight, *diaBox;
@@ -77,22 +81,26 @@ namespace ui
void init();
void exit();
//Adds a panel pointer to a vector since they need to be drawn over everything else
void addPanel(slideOutPanel *sop);
//Just draws a screen and flips JIC boot takes long.
void showLoadScreen();
//Clears and draws general stuff used by multiple screens
void drawUI();
//Draws selection box
void drawBoundBox(int x, int y, int w, int h, int clrSh);
//switch case so we don't have problems with multiple main loops like 3DS
void runApp(const uint64_t& down, const uint64_t& held);
bool runApp();
//These are shared by both folder menus
void createNewBackup(const uint64_t& held);
void overwriteBackup(unsigned ind);
void restoreBackup(unsigned ind);
void deleteBackup(unsigned ind);
}
//Expects a uint64_t passed for held buttons
void createNewBackup(void *a);
//all exepect an unsigned int containing menu's selected
void overwriteBackup(void *a);
void restoreBackup(void *a);
void deleteBackup(void *a);
#endif
//Used for multiple menu functions/callback
void toTTL(void *);
}

View File

@@ -1,15 +1,15 @@
#ifndef UISTR_H
#define UISTR_H
#pragma once
//Strings since translation support
namespace ui
{
extern const std::string loadGlyphArray[8];
void loadTrans();
extern std::string author, userHelp, titleHelp, folderHelp, optHelp, \
confBlacklist, confOverwrite, confRestore, confDel, confCopy, \
confEraseNand, confEraseFolder, yt, nt, on, off, confirmHead, \
copyHead, noSavesFound, errorConnecting, noUpdate;
copyHead, noSavesFound, errorConnecting, noUpdate, saveCreated, saveCreateFailed, \
saveDataReset, saveDataResetSuccess, saveDataDeleteSuccess;
//Strings for file mode menu
extern std::string advMenuStr[6];
@@ -17,12 +17,12 @@ namespace ui
extern std::string exMenuStr[11];
//Strings for options menu
extern std::string optMenuStr[15];
//Strings for options explanations
extern std::string optMenuExp[15];
//Strings for the holding thing
extern std::string holdingText[3];
//Strings for sort type
extern std::string sortString[3];
//Strings for user options
extern std::string usrOptString[1];
//Strings for title options
extern std::string titleOptString[4];
}
#endif // UISTR_H

View File

@@ -1,26 +0,0 @@
#ifndef UIUPDATE_H
#define UIUPDATE_H
//Contains declarations of ui updating functions
namespace ui
{
void updateUserMenu(const uint64_t& down, const uint64_t& held);
void drawUserMenu();
void updateTitleMenu(const uint64_t& down, const uint64_t& held);
void drawTitleMenu();
void updateFolderMenu(const uint64_t& down, const uint64_t& held);
void drawFolderMenu();
void updateAdvMode(const uint64_t& down, const uint64_t& held);
void drawAdvMode();
//needed here since it uses static menu
void folderMenuPrepare(data::user& usr, data::titledata& dat);
void advCopyMenuPrep();
void advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite);
}
#endif

10
inc/usr.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
namespace ui
{
void usrInit();
void usrExit();
void usrMenuSetActive(bool _set);
void usrUpdate();
void usrDraw(SDL_Texture *target);
}

View File

@@ -28,11 +28,11 @@ namespace util
std::string safeString(const std::string& s);
std::string getInfoString(const data::user& u, const data::titledata& d);
std::string getInfoString(data::user& u, const uint64_t& tid);
std::string getStringInput(const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]);
std::string generateAbbrev(const data::titledata& dat);
std::string generateAbbrev(const uint64_t& tid);
//removes char from C++ string
void stripChar(char _c, std::string& _s);
@@ -56,6 +56,33 @@ namespace util
return ret;
}
inline std::string getIDStr(const uint64_t& _id)
{
char tmp[18];
sprintf(tmp, "%016lX", _id);
return std::string(tmp);
}
inline std::string getIDStrLower(const uint64_t& _id)
{
char tmp[18];
sprintf(tmp, "%08X", (uint32_t)_id);
return std::string(tmp);
}
inline std::string generatePathByTID(const uint64_t& tid)
{
return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/";
}
inline void createTitleDirectoryByTID(const uint64_t& tid)
{
std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid);
mkdir(makePath.c_str(), 777);
}
Result accountDeleteUser(AccountUid *uid);
void setCPU(uint32_t hz);
void checkForUpdate();
}

View File

@@ -11,14 +11,8 @@
#include "file.h"
#include "util.h"
//Color for favorite hearts
const SDL_Color heartColor = {0xFF, 0x44, 0x44, 0xFF};
//FsSaveDataSpaceId_All doesn't work for SD
static const unsigned saveOrder [] =
{
0, 1, 2, 3, 4, 100, 101
};
static const unsigned saveOrder [] = { 0, 1, 2, 3, 4, 100, 101 };
int data::selUser = 0, data::selData = 0;
@@ -30,8 +24,8 @@ SetLanguage data::sysLang;
//Options
bool data::incDev = false, data::autoBack = true, data::ovrClk = false, data::holdDel = true, data::holdRest = true, data::holdOver = true;
bool data::forceMount = true, data::accSysSave = false, data::sysSaveWrite = false, data::directFsCmd = false, data::skipUser = false, data::zip = false;
bool data::langOverride = false;
bool data::forceMount = true, data::accSysSave = false, data::sysSaveWrite = false, data::directFsCmd = false, data::skipUser = false, data::zip = false, data::langOverride = false;
uint8_t data::sortType = 0;
//For other save types
@@ -40,25 +34,29 @@ static bool sysBCATPushed = false, cachePushed = false, tempPushed = false;
static std::vector<uint64_t> blacklist;
static std::vector<uint64_t> favorites;
static std::unordered_map<uint64_t, std::string> pathDefs;
std::unordered_map<uint64_t, SDL_Texture *> data::icons;
std::unordered_map<uint64_t, data::titleInfo> data::titles;
static SDL_Texture *iconMask;
//Sorts titles by sortType
static struct
{
bool operator()(const data::titledata& a, const data::titledata& b)
bool operator()(const data::userTitleInfo& a, const data::userTitleInfo& b)
{
//Favorites override EVERYTHING
if(a.getFav() != b.getFav()) return a.getFav();
if(data::isFavorite(a.saveID) != data::isFavorite(b.saveID)) return data::isFavorite(a.saveID);
switch(data::sortType)
{
case 0://Alpha
{
std::string titleA = data::getTitleNameByTID(a.saveID);
std::string titleB = data::getTitleNameByTID(b.saveID);
uint32_t tmpA, tmpB;
for(unsigned i = 0; i < a.getTitle().length(); )
for(unsigned i = 0; i < titleA.length(); )
{
ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&a.getTitle().data()[i]);
decode_utf8(&tmpB, (const uint8_t *)&b.getTitle().data()[i]);
ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&titleA.data()[i]);
decode_utf8(&tmpB, (const uint8_t *)&titleB.data()[i]);
tmpA = tolower(tmpA), tmpB = tolower(tmpB);
if(tmpA != tmpB)
return tmpA < tmpB;
@@ -69,11 +67,11 @@ static struct
break;
case 1://Most played
return a.getPlayTime() > b.getPlayTime();
return a.playStats.playtimeMinutes > b.playStats.playtimeMinutes;
break;
case 2://Last Played
return a.getLastTimeStamp() > b.getLastTimeStamp();
return a.playStats.last_timestampUser > b.playStats.last_timestampUser;
break;
}
return false;
@@ -98,7 +96,7 @@ static bool blacklisted(const uint64_t& tid)
return false;
}
static bool isFavorite(const uint64_t& tid)
bool data::isFavorite(const uint64_t& tid)
{
for(uint64_t& fid : favorites)
if(tid == fid) return true;
@@ -114,31 +112,6 @@ static bool isDefined(const uint64_t& id)
return false;
}
static SDL_Texture *createDeviceIcon()
{
return util::createIconGeneric("\ue121", 192);
}
static inline void loadCreateIcon(const uint64_t& _id, size_t _sz, const NsApplicationControlData *_d)
{
data::icons[_id] = gfx::loadJPEGMem(_d->icon, _sz);
}
static void loadCreateSystemIcon(const uint64_t& _id)
{
char tmp[16];
sprintf(tmp, "%08X", (uint32_t)_id);
data::icons[_id] = util::createIconGeneric(tmp, 32);
}
static inline std::string getIDStr(const uint64_t& _id)
{
char tmp[18];
sprintf(tmp, "%016lX", _id);
return std::string(tmp);
}
static inline bool accountSystemSaveCheck(const FsSaveDataInfo& _inf)
{
if(_inf.save_data_type == FsSaveDataType_System && util::accountUIDToU128(_inf.uid) != 0 && !data::accSysSave)
@@ -150,30 +123,92 @@ static inline bool accountSystemSaveCheck(const FsSaveDataInfo& _inf)
//Minimal init/test to avoid loading and creating things I don't need
static bool testMount(const FsSaveDataInfo& _inf)
{
bool ret = false;
if(!data::forceMount)
return true;
bool ret = false;
uint64_t id;
data::user tmpusr;
data::titledata tmpdat;
if(_inf.save_data_type == FsSaveDataType_System || _inf.save_data_type == FsSaveDataType_SystemBcat)
id = _inf.system_save_data_id;
else
id = _inf.application_id;
tmpusr.setUID(_inf.uid);
tmpdat.setID(id);
tmpdat.setIndex(_inf.save_data_index);
tmpdat.setType((FsSaveDataType)_inf.save_data_type);
if((ret = fs::mountSave(tmpusr, tmpdat)))
if((ret = fs::mountSave(_inf)))
fs::unmountSave();
return ret;
}
static inline void addTitleToList(const uint64_t& tid)
{
uint64_t outSize = 0;
NsApplicationControlData *ctrlData = new NsApplicationControlData;
NacpLanguageEntry *ent;
Result ctrlRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, ctrlData, sizeof(NsApplicationControlData), &outSize);
Result nacpRes = nacpGetLanguageEntry(&ctrlData->nacp, &ent);
size_t iconSize = outSize - sizeof(ctrlData->nacp);
if(R_SUCCEEDED(ctrlRes) && !(outSize < sizeof(ctrlData->nacp)) && R_SUCCEEDED(nacpRes) && iconSize > 0)
{
//Copy nacp
memcpy(&data::titles[tid].nacp, &ctrlData->nacp, sizeof(NacpStruct));
//Setup 'shortcuts' to strings
NacpLanguageEntry *ent;
nacpGetLanguageEntry(&data::titles[tid].nacp, &ent);
data::titles[tid].title = ent->name;
data::titles[tid].author = ent->author;
if(isDefined(tid))
data::titles[tid].safeTitle = pathDefs[tid];
else if((data::titles[tid].safeTitle = util::safeString(ent->name)) == "")
data::titles[tid].safeTitle = util::getIDStr(tid);
if(data::isFavorite(tid))
data::titles[tid].fav = true;
data::titles[tid].icon = gfx::loadJPEGMem(ctrlData->icon, iconSize);
}
else
{
memset(&data::titles[tid].nacp, 0, sizeof(NacpStruct));
data::titles[tid].title = util::getIDStr(tid);
data::titles[tid].author = "Someone?";
if(isDefined(tid))
data::titles[tid].safeTitle = pathDefs[tid];
else
data::titles[tid].safeTitle = util::getIDStr(tid);
data::titles[tid].icon = util::createIconGeneric(util::getIDStrLower(tid).c_str(), 32);
}
delete ctrlData;
}
static inline bool titleIsLoaded(const uint64_t& tid)
{
auto findTid = data::titles.find(tid);
return findTid == data::titles.end() ? false : true;
}
static void loadUserAccounts()
{
s32 total = 0;
AccountUid *uids = new AccountUid[8];
if(R_SUCCEEDED(accountListAllUsers(uids, 8, &total)))
{
for(int i = 0; i < total; i++)
data::users.emplace_back(uids[i], "");
}
delete[] uids;
}
//This can load titles installed without having save data
static void loadTitlesFromRecords()
{
NsApplicationRecord nsRecord;
int32_t entryCount = 0, recordOffset = 0;
while(R_SUCCEEDED(nsListApplicationRecord(&nsRecord, 1, recordOffset++, &entryCount)) && entryCount > 0)
{
if(!titleIsLoaded(nsRecord.application_id))
addTitleToList(nsRecord.application_id);
}
}
bool data::loadUsersTitles(bool clearUsers)
{
static unsigned systemUserCount = 3;
@@ -181,25 +216,28 @@ bool data::loadUsersTitles(bool clearUsers)
FsSaveDataInfo info;
s64 total = 0;
loadTitlesFromRecords();
//Clear titles
for(data::user& u : data::users)
u.titles.clear();
u.titleInfo.clear();
if(clearUsers)
{
systemUserCount = 3;
systemUserCount = 4;
for(data::user& u : data::users)
u.delIcon();
data::users.clear();
loadUserAccounts();
sysBCATPushed = false;
cachePushed = false;
tempPushed = false;
users.emplace_back(util::u128ToAccountUID(3), "Device Saves", createDeviceIcon());
users.emplace_back(util::u128ToAccountUID(3), "Device");
users.emplace_back(util::u128ToAccountUID(2), "BCAT");
users.emplace_back(util::u128ToAccountUID(5), "Cache");
users.emplace_back(util::u128ToAccountUID(0), "System");
}
NsApplicationControlData *dat = new NsApplicationControlData;
for(unsigned i = 0; i < 7; i++)
{
if(R_FAILED(fsOpenSaveDataInfoReader(&it, (FsSaveDataSpaceId)saveOrder[i])))
@@ -207,8 +245,14 @@ bool data::loadUsersTitles(bool clearUsers)
while(R_SUCCEEDED(fsSaveDataInfoReaderRead(&it, &info, 1, &total)) && total != 0)
{
uint64_t saveID = 0;
if(info.save_data_type == FsSaveDataType_System || info.save_data_type == FsSaveDataType_SystemBcat)
saveID = info.system_save_data_id;
else
saveID = info.application_id;
//Don't bother with this stuff
if(blacklisted(info.application_id) || blacklisted(info.save_data_id) || !accountSystemSaveCheck(info) || !testMount(info))
if(blacklisted(saveID) || !accountSystemSaveCheck(info) || !testMount(info))
continue;
switch(info.save_data_type)
@@ -252,35 +296,41 @@ bool data::loadUsersTitles(bool clearUsers)
break;
}
if(!titleIsLoaded(saveID))
addTitleToList(saveID);
int u = getUserIndex(info.uid);
if(u == -1)
{
users.emplace(data::users.end() - systemUserCount, info.uid, "");
u = getUserIndex(info.uid);
}
users[u].titles.emplace_back(info, dat);
PdmPlayStatistics playStats;
if(info.save_data_type == FsSaveDataType_Account || info.save_data_type == FsSaveDataType_Device)
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(info.application_id, info.uid, false, &playStats);
else
memset(&playStats, 0, sizeof(PdmPlayStatistics));
users[u].addUserTitleInfo(saveID, &info, &playStats);
}
fsSaveDataInfoReaderClose(&it);
}
delete dat;
if(data::incDev)
/*if(data::incDev)
{
//Get reference to device save user
data::user& dev = data::users[data::users.size() - 3];
for(unsigned i = 0; i < users.size() - 3; i++)
data::user& dev = data::users[data::users.size() - 4];
for(unsigned i = 0; i < users.size() - 4; i++)
{
//Not needed but makes this easier to read
data::user& u = data::users[i];
u.titles.insert(u.titles.end(), dev.titles.begin(), dev.titles.end());
}
}
}*/
for(data::user& u : data::users)
{
u.loadPlayTimes();
std::sort(u.titles.begin(), u.titles.end(), sortTitles);
}
std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles);
return true;
}
@@ -305,11 +355,10 @@ void data::init()
void data::exit()
{
for(data::user& u : data::users) u.delIcon();
for(auto& icn : icons)
{
if(icn.second)
SDL_DestroyTexture(icn.second);
}
for(auto& tinfo : titles)
SDL_DestroyTexture(tinfo.second.icon);
SDL_DestroyTexture(iconMask);
saveFav();
saveCfg();
@@ -317,95 +366,24 @@ void data::exit()
util::setCPU(1020000000);
}
data::titledata::titledata(const FsSaveDataInfo& inf, NsApplicationControlData *dat)
data::titleInfo *data::getTitleInfoByTID(const uint64_t& tid)
{
size_t outSz = 0;
NacpLanguageEntry *ent = NULL;
memset(dat, 0, sizeof(NsApplicationControlData));
if(inf.save_data_type == FsSaveDataType_System || inf.save_data_type == FsSaveDataType_SystemBcat)
id = inf.system_save_data_id;
else
id = inf.application_id;
saveID = inf.save_data_id;
saveIndex = inf.save_data_index;
saveDataType = inf.save_data_type;
Result ctrlDataRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, id, dat, sizeof(NsApplicationControlData), &outSz);
Result nacpRes = nacpGetLanguageEntry(&dat->nacp, &ent);
size_t icnSize = outSz - sizeof(dat->nacp);
auto icnInd = icons.find(id);
if(R_SUCCEEDED(ctrlDataRes) && !(outSz < sizeof(dat->nacp)) && R_SUCCEEDED(nacpRes) && ent != NULL && icnSize > 0)
{
title.assign(ent->name);
author.assign(ent->author);
if(isDefined(id))
titleSafe = util::safeString(pathDefs[id]);
else if((titleSafe = util::safeString(title)) == "")
titleSafe = getIDStr(id);
if(icnInd == icons.end())
loadCreateIcon(id, icnSize, dat);
assignIcon();
}
else
{
if(icnInd == icons.end())
loadCreateSystemIcon(id);
title = getIDStr(id);
titleSafe = getIDStr(id);
assignIcon();
}
favorite = isFavorite(id);
return &titles[tid];
}
void data::titledata::createDir() const
std::string data::getTitleNameByTID(const uint64_t& tid)
{
mkdir(std::string(fs::getWorkDir() + titleSafe).c_str(), 777);
return titles[tid].title;
}
std::string data::titledata::getPath() const
std::string data::getTitleSafeNameByTID(const uint64_t& tid)
{
return std::string(fs::getWorkDir() + titleSafe + "/");
return titles[tid].safeTitle;
}
std::string data::titledata::getTIDStr() const
SDL_Texture *data::getTitleIconByTID(const uint64_t& tid)
{
return getIDStr(id);
}
std::string data::titledata::getSaveIDStr() const
{
return getIDStr(saveID);
}
void data::titledata::assignIcon()
{
icon = icons[id];
}
void data::titledata::drawIcon(bool full, unsigned x, unsigned y)
{
if(full)
gfx::texDraw(icon, x, y);
else
gfx::texDrawStretch(icon, x, y, 128, 128);
}
void data::titledata::drawIconFav(bool full, unsigned x, unsigned y)
{
if(full)
{
gfx::texDraw(icon, x, y);
gfx::drawTextf(48, x + 16, y + 16, &heartColor, "");
}
else
{
gfx::texDrawStretch(icon, x, y, 128, 128);
gfx::drawTextf(24, x + 8, y + 8, &heartColor, "");
}
return titles[tid].icon;
}
data::user::user(const AccountUid& _id, const std::string& _backupName)
@@ -438,17 +416,18 @@ data::user::user(const AccountUid& _id, const std::string& _backupName)
}
else
{
username = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName;
userSafe = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName;
userIcon = util::createIconGeneric(_backupName.c_str(), 32);
username = _backupName.empty() ? util::getIDStr((uint64_t)uID128) : _backupName;
userSafe = _backupName.empty() ? util::getIDStr((uint64_t)uID128) : _backupName;
userIcon = util::createIconGeneric(_backupName.c_str(), 40);
}
titles.reserve(32);
titles.reserve(64);
}
data::user::user(const AccountUid& _id, const std::string& _backupName, SDL_Texture *img) : user(_id, _backupName)
{
delIcon();
userIcon = img;
titles.reserve(64);
}
void data::user::setUID(const AccountUid& _id)
@@ -457,52 +436,13 @@ void data::user::setUID(const AccountUid& _id)
uID128 = util::accountUIDToU128(_id);
}
void data::user::loadPlayTimes()
void data::user::addUserTitleInfo(const uint64_t& tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats)
{
PdmPlayStatistics stats;
for(data::titledata& _d : titles)
{
switch(_d.getType())
{
case FsSaveDataType_Account:
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(_d.getID(), userID, false, &stats);
_d.setPlayTime(stats.playtimeMinutes);
_d.setLastTimeStamp(stats.last_timestampUser);
_d.setLaunchCount(stats.totalLaunches);
break;
case FsSaveDataType_Device:
pdmqryQueryPlayStatisticsByApplicationId(_d.getID(), false, &stats);
_d.setPlayTime(stats.playtimeMinutes);
_d.setLastTimeStamp(stats.last_timestampNetwork);
_d.setLaunchCount(stats.totalLaunches);
break;
default:
_d.setPlayTime(0);
_d.setLastTimeStamp(0);
_d.setLaunchCount(0);
break;
}
}
}
unsigned data::getTotalSaves()
{
unsigned ret = 0;
FsSaveDataInfoReader read;
FsSaveDataInfo tmp;
int64_t out = 0;
for(unsigned i = 0; i < 7; i++)
{
if(R_FAILED(fsOpenSaveDataInfoReader(&read, (FsSaveDataSpaceId)saveOrder[i])))
continue;
while(R_SUCCEEDED(fsSaveDataInfoReaderRead(&read, &tmp, 1, &out)) && out != 0)
++ret;
}
fsSaveDataInfoReaderClose(&read);
return ret;
data::userTitleInfo newInfo;
newInfo.saveID = tid;
memcpy(&newInfo.saveInfo, _saveInfo, sizeof(FsSaveDataInfo));
memcpy(&newInfo.playStats, _stats, sizeof(PdmPlayStatistics));
titleInfo.emplace_back(newInfo);
}
void data::loadBlacklist()
@@ -519,49 +459,38 @@ void data::saveBlackList()
{
std::string blPath = fs::getWorkDir() + "blacklist.txt";
FILE *bl = fopen(blPath.c_str(), "w");
for(uint64_t& id : blacklist)
fprintf(bl, "0x%016lX\n", id);
for(uint64_t id : blacklist)
fprintf(bl, "#%s\n0x%016lX\n", data::getTitleNameByTID(id).c_str(), id);
fclose(bl);
}
void data::blacklistAdd(titledata& t)
void data::blacklistAdd(const uint64_t& tid)
{
uint64_t tid = t.getID();
for(data::user& _u : data::users)
{
for(unsigned i = 0; i < _u.titles.size(); i++)
if(_u.titles[i].getID() == tid) _u.titles.erase(_u.titles.begin() + i);
for(unsigned i = 0; i < _u.titleInfo.size(); i++)
if(_u.titleInfo[i].saveID == tid) _u.titleInfo.erase(_u.titleInfo.begin() + i);
}
blacklist.push_back(tid);
}
void data::favoriteTitle(titledata& t)
void data::favoriteTitle(const uint64_t& tid)
{
uint64_t tid = t.getID();
if(!t.getFav())
if(!isFavorite(tid))
{
for(data::user& _u : data::users)
{
for(unsigned i = 0; i < _u.titles.size(); i++)
if(_u.titles[i].getID() == tid) _u.titles[i].setFav(true);
std::sort(_u.titles.begin(), _u.titles.end(), sortTitles);
}
titles[tid].fav = true;
favorites.push_back(tid);
}
else
{
titles[tid].fav = false;
auto ind = std::find(favorites.begin(), favorites.end(), tid);
favorites.erase(ind);
for(data::user& _u : data::users)
{
for(unsigned i = 0; i < _u.titles.size(); i++)
if(_u.titles[i].getID() == tid) _u.titles[i].setFav(false);
std::sort(_u.titles.begin(), _u.titles.end(), sortTitles);
}
}
for(auto &u : data::users)
std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles);
}
void data::loadCfg()
@@ -585,7 +514,6 @@ void data::loadCfg()
data::forceMount = cfgIn >> 57 & 1;
data::accSysSave = cfgIn >> 56 & 1;
data::sysSaveWrite = cfgIn >> 55 & 1;
ui::textMode = cfgIn >> 54 & 1;
data::directFsCmd = cfgIn >> 53 & 1;
data::skipUser = cfgIn >> 52 & 1;
data::zip = cfgIn >> 51 & 1;
@@ -609,7 +537,6 @@ void data::saveCfg()
cfgOut |= (uint64_t)data::forceMount << 57;
cfgOut |= (uint64_t)data::accSysSave << 56;
cfgOut |= (uint64_t)data::sysSaveWrite << 55;
cfgOut |= (uint64_t)ui::textMode << 54;
cfgOut |= (uint64_t)data::directFsCmd << 53;
cfgOut |= (uint64_t)data::skipUser << 52;
cfgOut |= (uint64_t)data::zip << 51;
@@ -636,7 +563,6 @@ void data::restoreDefaultConfig()
data::skipUser = false;
data::zip = false;
data::sortType = 0;
data::langOverride = false;
}
void data::loadFav()
@@ -680,11 +606,10 @@ void data::dispStats()
//Easiest/laziest way to do this
std::string stats = "User Count: " + std::to_string(users.size()) + "\n";
for(data::user& u : data::users)
stats += u.getUsername() + ": " + std::to_string(u.titles.size()) + "\n";
stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n";
stats += "Current User: " + data::curUser.getUsername() + "\n";
stats += "Current Title: " + data::curData.getTitle() + "\n";
stats += "Safe Title: " + data::curData.getTitleSafe() + "\n";
stats += "Icon count: " + std::to_string(icons.size()) + "\n";
stats += "Current Title: " + data::getTitleNameByTID(data::curData.saveID) + "\n";
stats += "Safe Title: " + data::getTitleSafeNameByTID(data::curData.saveID) + "\n";
stats += "Sort Type: " + std::to_string(data::sortType) + "\n";
gfx::drawTextf(16, 8, 8, &green, stats.c_str());
gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str());
}

View File

@@ -131,25 +131,25 @@ void fs::exit()
fs::logClose();
}
bool fs::mountSave(const data::user& usr, const data::titledata& open)
bool fs::mountSave(const FsSaveDataInfo& _m)
{
Result svOpen;
switch(open.getType())
switch(_m.save_data_type)
{
case FsSaveDataType_System:
svOpen = fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, open.getID(), usr.getUID());
svOpen = fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, _m.save_data_id, _m.uid);
break;
case FsSaveDataType_Account:
svOpen = fsOpen_SaveData(&sv, open.getID(), usr.getUID());
svOpen = fsOpen_SaveData(&sv, _m.application_id, _m.uid);
break;
case FsSaveDataType_Bcat:
svOpen = fsOpen_BcatSaveData(&sv, open.getID());
svOpen = fsOpen_BcatSaveData(&sv, _m.application_id);
break;
case FsSaveDataType_Device:
svOpen = fsOpen_DeviceSaveData(&sv, open.getID());
svOpen = fsOpen_DeviceSaveData(&sv, _m.application_id);
break;
case FsSaveDataType_Temporary:
@@ -157,11 +157,11 @@ bool fs::mountSave(const data::user& usr, const data::titledata& open)
break;
case FsSaveDataType_Cache:
svOpen = fsOpen_CacheStorage(&sv, open.getID(), open.getSaveIndex());
svOpen = fsOpen_CacheStorage(&sv, _m.application_id, _m.save_data_rank);
break;
case FsSaveDataType_SystemBcat:
svOpen = fsOpen_SystemBcatSaveData(&sv, open.getID());
svOpen = fsOpen_SystemBcatSaveData(&sv, _m.application_id);
break;
default:
@@ -371,7 +371,7 @@ void fs::copyFile(const std::string& from, const std::string& to)
copyArgs *send = copyArgsCreate(from, to, "", NULL, &progress);
//Setup progress bar. This thread updates screen, other handles copying
ui::progBar prog(fsize(from), PROG_MAX_WIDTH_DEFAULT);
ui::progBar prog(fsize(from));
Thread cpyThread;
threadCreate(&cpyThread, copyfile_t, send, NULL, 0x4000, 0x2B, 1);
@@ -448,7 +448,7 @@ void copyFileCommit_t(void *a)
void fs::copyFileCommit(const std::string& from, const std::string& to, const std::string& dev)
{
uint64_t offset = 0;
ui::progBar prog(fsize(from), PROG_MAX_WIDTH_DEFAULT);
ui::progBar prog(fsize(from));
copyArgs *send = copyArgsCreate(from, to, dev, NULL, &offset);
Thread cpyThread;
@@ -501,7 +501,7 @@ void copyFileToZip_t(void *a)
{
if(zipWriteInFileInZip(*args->z, inBuff, readIn) != 0)
{
fs::logWrite("zipWriteInFileInZip failed -> \"%s\"\n", args->from.c_str());
fs::logWrite("Failed", "zipWriteInFileInZip -> \"%s\"\n", args->from.c_str());
break;
}
@@ -515,7 +515,7 @@ void copyFileToZip_t(void *a)
void copyFileToZip(const std::string& from, zipFile *z)
{
ui::progBar prog(fs::fsize(from), PROG_MAX_WIDTH_DEFAULT);
ui::progBar prog(fs::fsize(from));
uint64_t progress = 0;
copyArgs *send = copyArgsCreate(from, "", "", z, &progress);
@@ -571,7 +571,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de
{
std::string path = to + filename;
mkdirRec(path.substr(0, path.find_last_of('/') + 1));
ui::progBar prog(info.uncompressed_size, PROG_MAX_WIDTH_DEFAULT);
ui::progBar prog(info.uncompressed_size);
size_t done = 0;
//Create new empty file using FS
@@ -584,6 +584,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de
done += readIn;
fwriteCommit(path, buff, readIn, dev);
prog.update(done);
prog.draw(filename, ui::copyHead);
gfx::present();
}
@@ -595,6 +596,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de
done += readIn;
fwriteCommit(path, buff, readIn, dev);
prog.update(done);
prog.draw(filename, ui::copyHead);
gfx::present();
}
@@ -697,23 +699,22 @@ void fs::freePathFilters()
bool fs::dumpAllUserSaves(const data::user& u)
{
for(unsigned i = 0; i < u.titles.size(); i++)
for(unsigned i = 0; i < u.titleInfo.size(); i++)
{
ui::updatePad();
ui::updateInput();
if(ui::padKeysDown() & HidNpadButton_B)
return false;
if(fs::mountSave(u, u.titles[i]))
if(fs::mountSave(u.titleInfo[i].saveInfo))
{
u.titles[i].createDir();
std::string filtersPath = u.titles[i].getPath() + "pathFilters.txt";
fs::loadPathFilters(filtersPath);
util::createTitleDirectoryByTID(u.titleInfo[i].saveID);
std::string basePath = util::generatePathByTID(u.titleInfo[i].saveID);
switch(data::zip)
{
case true:
{
std::string outPath = u.titles[i].getPath() + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
std::string outPath = basePath + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen(outPath.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
@@ -722,16 +723,18 @@ bool fs::dumpAllUserSaves(const data::user& u)
case false:
{
std::string outPath = u.titles[i].getPath() + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
std::string outPath = basePath + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
mkdir(outPath.substr(0, outPath.length() - 1).c_str(), 777);
fs::copyDirToDir("sv:/", outPath);
}
break;
}
fsdevUnmountDevice("sv");
fs::freePathFilters();
}
}
ui::updateInput();
return true;//?
}
@@ -825,6 +828,176 @@ bool fs::isDir(const std::string& _path)
return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode);
}
void fs::createNewBackup(void *a)
{
uint64_t held = ui::padKeysHeld();
std::string out;
if(held & HidNpadButton_R)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
else if(held & HidNpadButton_L)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM);
else if(held & HidNpadButton_ZL)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE);
else
{
const std::string dict[] =
{
util::getDateTime(util::DATE_FMT_YMD),
util::getDateTime(util::DATE_FMT_YDM),
util::getDateTime(util::DATE_FMT_HOYSTE),
util::getDateTime(util::DATE_FMT_JHK),
util::getDateTime(util::DATE_FMT_ASC),
data::users[data::selUser].getUsernameSafe(),
data::getTitleInfoByTID(data::curData.saveID)->safeTitle,
util::generateAbbrev(data::curData.saveID)
};
out = util::getStringInput("", "Enter a name", 64, 8, dict);
}
if(!out.empty())
{
std::string path = util::generatePathByTID(data::curData.saveID) + out;
switch(data::zip)
{
case true:
{
path += ".zip";
zipFile zip = zipOpen(path.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
break;
case false:
{
mkdir(path.c_str(), 777);
path += "/";
fs::copyDirToDir("sv:/", path);
}
break;
}
ui::fldInit();
}
}
void fs::overwriteBackup(void *a)
{
fs::backupArgs *in = (fs::backupArgs *)a;
ui::menu *m = in->m;
fs::dirList *d = in->d;
unsigned ind = m->getSelected() - 1;;//Skip new
std::string itemName = d->getItem(ind);
if(ui::confirm(data::holdOver, ui::confOverwrite.c_str(), itemName.c_str()))
{
if(d->isDir(ind))
{
std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
//Delete and recreate
fs::delDir(toPath);
mkdir(toPath.c_str(), 777);
fs::copyDirToDir("sv:/", toPath);
}
else if(!d->isDir(ind) && d->getItemExt(ind) == "zip")
{
std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName;
fs::delfile(toPath);
zipFile zip = zipOpen(toPath.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
}
}
void fs::restoreBackup(void *a)
{
fs::backupArgs *in = (fs::backupArgs *)a;
ui::menu *m = in->m;
fs::dirList *d = in->d;
unsigned ind = m->getSelected() - 1;
std::string itemName = d->getItem(ind);
if((data::curData.saveInfo.save_data_type != FsSaveDataType_System || data::sysSaveWrite) && m->getSelected() > 0 && ui::confirm(data::holdRest, ui::confRestore.c_str(), itemName.c_str()))
{
if(data::autoBack)
{
switch(data::zip)
{
case true:
{
std::string autoZip = util::generatePathByTID(data::curData.saveID) + "/AUTO " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen(autoZip.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
break;
case false:
{
std::string autoFolder = util::generatePathByTID(data::curData.saveID) + "/AUTO - " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
mkdir(autoFolder.substr(0, autoFolder.length() - 1).c_str(), 777);
fs::copyDirToDir("sv:/", autoFolder);
}
break;
}
}
if(d->isDir(ind))
{
fs::wipeSave();
std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
fs::copyDirToDirCommit(fromPath, "sv:/", "sv");
}
else if(!d->isDir(ind) && d->getItemExt(ind) == "zip")
{
fs::wipeSave();
std::string path = util::generatePathByTID(data::curData.saveID) + itemName;
unzFile unz = unzOpen(path.c_str());
fs::copyZipToDir(&unz, "sv:/", "sv");
unzClose(unz);
}
else
{
//Just copy file over
std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName;
std::string toPath = "sv:/" + itemName;
fs::copyFileCommit(fromPath, toPath, "sv");
}
}
if(data::autoBack)
ui::fldInit();
}
void fs::deleteBackup(void *a)
{
fs::backupArgs *in = (fs::backupArgs *)a;
ui::menu *m = in->m;
fs::dirList *d = in->d;
unsigned ind = m->getSelected() - 1;
std::string itemName = d->getItem(ind);
if(ui::confirmDelete(itemName))
{
if(d->isDir(ind))
{
std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
fs::delDir(delPath);
}
else
{
std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName;
fs::delfile(delPath);
}
ui::fldInit();
}
}
void fs::logOpen()
{
std::string logPath = wd + "log.txt";

View File

@@ -9,6 +9,7 @@
#define VA_SIZE 1024
#include "gfx.h"
#include "file.h"
static SDL_Window *wind;
SDL_Renderer *gfx::render;
@@ -29,6 +30,8 @@ static const uint32_t greenMask = 0x00FF0000;
static const uint32_t blueMask = 0x0000FF00;
static const uint32_t alphaMask = 0x000000FF;
static uint8_t *alphaMod;
static inline bool compClr(const SDL_Color *c1, const SDL_Color *c2)
{
return (c1->r == c2->r) && (c1->b == c2->b) && (c1->g == c2->g) && (c1->a == c2->a);
@@ -97,6 +100,15 @@ void gfx::init()
wind = SDL_CreateWindow("JKSV", 0, 0, 1280, 720, SDL_WINDOW_SHOWN);
render = SDL_CreateRenderer(wind, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
//Load the alpha mod to round icon corners
alphaMod = (uint8_t *)malloc(256 * 256);
FILE *modLoad = fopen("romfs:/img/icn/icon.msk", "rb");
fread(alphaMod, 1, 256 * 256, modLoad);
fclose(modLoad);
loadSystemFont();
}
@@ -106,16 +118,12 @@ void gfx::exit()
SDL_Quit();
freeSystemFont();
free(alphaMod);
for(auto c : glyphCache)
SDL_DestroyTexture(c.second.tex);
}
void gfx::clear(const SDL_Color *c)
{
SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a);
SDL_RenderClear(render);
}
void gfx::present()
{
SDL_RenderPresent(render);
@@ -131,6 +139,9 @@ SDL_Texture *gfx::loadJPEGMem(const void *jpegData, size_t jpegsize)
SDL_FreeSurface(tmpSurf);
SDL_RWclose(jpeg);
SDL_SetTextureBlendMode(ret, SDL_BLENDMODE_BLEND);
return ret;
}
@@ -142,6 +153,9 @@ SDL_Texture *gfx::loadImageFile(const char *file)
ret = SDL_CreateTextureFromSurface(render, tmpSurf);
SDL_FreeSurface(tmpSurf);
SDL_SetTextureBlendMode(ret, SDL_BLENDMODE_BLEND);
return ret;
}
@@ -245,8 +259,9 @@ static inline bool specialChar(const uint32_t *p, const int *fontSize, const SDL
return ret;
}
void gfx::drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...)
void gfx::drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...)
{
SDL_SetRenderTarget(gfx::render, target);
char tmp[VA_SIZE];
va_list args;
va_start(args, fmt);
@@ -283,10 +298,12 @@ void gfx::drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *
tmpX += g->advX;
}
}
SDL_SetRenderTarget(gfx::render, NULL);
}
void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color *c, const char *fmt, ...)
void gfx::drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color *c, const char *fmt, ...)
{
SDL_SetRenderTarget(gfx::render, target);
char tmp[VA_SIZE], wordBuff[128];
va_list args;
va_start(args, fmt);
@@ -307,7 +324,7 @@ void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Colo
size_t width = gfx::getTextWidth(wordBuff, fontSize);
if(tmpX + width >= x + maxWidth)
if((int)(tmpX + width) >= (int)(x + maxWidth))
{
tmpX = x;
y += fontSize + 8;
@@ -339,6 +356,7 @@ void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Colo
}
i += wordLength;
}
SDL_SetRenderTarget(gfx::render, NULL);
}
size_t gfx::getTextWidth(const char *str, int fontSize)

View File

@@ -1,13 +1,9 @@
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <switch.h>
#include "gfx.h"
#include "file.h"
#include "data.h"
#include "ui.h"
#include "file.h"
#include "util.h"
extern "C"
@@ -19,7 +15,7 @@ extern "C"
nsInitialize();
setsysInitialize();
setInitialize();
accountInitialize(AccountServiceType_System);
accountInitialize(AccountServiceType_Administrator);
pmshellInitialize();
socketInitializeDefault();
pdmqryInitialize();
@@ -39,8 +35,6 @@ extern "C"
}
}
bool debDataStats = false;
int main(int argc, const char *argv[])
{
romfsInit();
@@ -52,23 +46,7 @@ int main(int argc, const char *argv[])
ui::init();
romfsExit();
while(appletMainLoop())
{
ui::updatePad();
uint64_t down = ui::padKeysDown(), held = ui::padKeysHeld();
if(held & HidNpadButton_StickL && held & HidNpadButton_StickR)
debDataStats = true;
else if(down & HidNpadButton_Plus)
break;
ui::runApp(down, held);
if(debDataStats)
data::dispStats();
gfx::present();
}
while(ui::runApp()){ }
ui::exit();
data::exit();

View File

@@ -2,22 +2,21 @@
#include <unordered_map>
#include <cstdio>
#include <cstring>
#include <vector>
#include <sys/stat.h>
#include <switch.h>
#include "file.h"
#include "ui.h"
#include "gfx.h"
#include "util.h"
#include "file.h"
//text mode
bool ui::textMode = false;
//Current menu state
int ui::mstate = USR_SEL, ui::prevState = USR_SEL;
//pad data?
PadState ui::pad;
HidTouchScreenState ui::touchState;
//Theme id
ColorSetId ui::thmID;
@@ -26,7 +25,8 @@ ColorSetId ui::thmID;
std::string ui::folderMenuInfo;
//UI colors
SDL_Color ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, divClr;
SDL_Color ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, ui::divClr, ui::slidePanelColor;
SDL_Color ui::transparent = {0x00, 0x00, 0x00, 0x00};
//textbox pieces
//I was going to flip them when I draw them, but then laziness kicked in.
@@ -36,194 +36,23 @@ SDL_Texture *ui::cornerTopLeft, *ui::cornerTopRight, *ui::cornerBottomLeft, *ui:
SDL_Texture *ui::progCovLeft, *ui::progCovRight, *ui::diaBox;
//Menu box pieces
SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
SDL_Texture *ui::mnuTopLeft, *ui::mnuTopRight, *ui::mnuBotLeft, *ui::mnuBotRight;
//Select box + top left icon
SDL_Texture *ui::sideBar;
static SDL_Texture *icn;
static SDL_Texture *icn, *leftPanel, *rightPanel;
static SDL_Color rectTop = {0x36, 0x36, 0x36, 0xFF};
SDL_Color ui::heartColor = {0xFF, 0x44, 0x44, 0xFF};
//X position of help texts. Calculated to make editing quicker/easier
static unsigned userHelpX, titleHelpX, folderHelpX, optHelpX;
//Map to associate external string names to unsigned ints for switch case.
static std::unordered_map<std::string, unsigned> uistrdef =
{
{"author", 0}, {"userHelp", 1}, {"titleHelp", 2}, {"folderHelp", 3}, {"optHelp", 4},
{"yt", 5}, {"nt", 6}, {"on", 7}, {"off", 8}, {"confirmBlacklist", 9}, {"confirmOverwrite", 10},
{"confirmRestore", 11}, {"confirmDelete", 12}, {"confirmCopy", 13}, {"confirmEraseNand", 14},
{"confirmEraseFolder", 15}, {"confirmHead", 16}, {"copyHead", 17}, {"noSavesFound", 18},
{"advMenu", 19}, {"extMenu", 20}, {"optMenu", 21}, {"optMenuExp", 22}, {"holdingText", 23},
{"errorConnecting", 24}, {"noUpdate", 25}, {"sortType", 26}
};
//For shrinking left panel
unsigned leftWidth = 410;
static void loadTrans()
{
bool transFile = fs::fileExists(fs::getWorkDir() + "trans.txt");
if(!transFile && (data::sysLang == SetLanguage_ENUS || data::langOverride))
return;//Don't bother loading from file. It serves as a translation guide
std::string file;
if(transFile)
file = fs::getWorkDir() + "trans.txt";
else
{
file = "romfs:/lang/";
switch(data::sysLang)
{
case SetLanguage_ZHCN:
case SetLanguage_ZHHANS:
file += "zh-CN.txt";
break;
case SetLanguage_ZHTW:
case SetLanguage_ZHHANT:
file += "zh-TW.txt";
break;
default:
return;
break;
}
}
fs::dataFile lang(file);
while(lang.readNextLine(true))
{
switch(uistrdef[lang.getName()])
{
case 0:
ui::author = lang.getNextValueStr();
break;
case 1:
ui::userHelp = lang.getNextValueStr();
break;
case 2:
ui::titleHelp = lang.getNextValueStr();
break;
case 3:
ui::folderHelp = lang.getNextValueStr();
break;
case 4:
ui::optHelp = lang.getNextValueStr();
break;
case 5:
ui::yt = lang.getNextValueStr();
break;
case 6:
ui::nt = lang.getNextValueStr();
break;
case 7:
ui::on = lang.getNextValueStr();
break;
case 8:
ui::off = lang.getNextValueStr();
break;
case 9:
ui::confBlacklist = lang.getNextValueStr();
break;
case 10:
ui::confOverwrite = lang.getNextValueStr();
break;
case 11:
ui::confRestore = lang.getNextValueStr();
break;
case 12:
ui::confDel = lang.getNextValueStr();
break;
case 13:
ui::confCopy = lang.getNextValueStr();
break;
case 14:
ui::confEraseNand = lang.getNextValueStr();
break;
case 15:
ui::confEraseFolder = lang.getNextValueStr();
break;
case 16:
ui::confirmHead = lang.getNextValueStr();
break;
case 17:
ui::copyHead = lang.getNextValueStr();
break;
case 18:
ui::noSavesFound = lang.getNextValueStr();
break;
case 19:
{
int ind = lang.getNextValueInt();
ui::advMenuStr[ind] = lang.getNextValueStr();
}
break;
case 20:
{
int ind = lang.getNextValueInt();
ui::exMenuStr[ind] = lang.getNextValueStr();
}
break;
case 21:
{
int ind = lang.getNextValueInt();
ui::optMenuStr[ind] = lang.getNextValueStr();
}
break;
case 22:
{
int ind = lang.getNextValueInt();
ui::optMenuExp[ind] = lang.getNextValueStr();
}
break;
case 23:
{
int ind = lang.getNextValueInt();
ui::holdingText[ind] = lang.getNextValueStr();
}
break;
case 24:
ui::errorConnecting = lang.getNextValueStr();
break;
case 25:
ui::noUpdate = lang.getNextValueStr();
break;
case 26:
{
int ind = lang.getNextValueInt();
ui::sortString[ind] = lang.getNextValueStr();
}
break;
default:
ui::showMessage("*Translation File Error:*", "On Line: %s\n*%s* is not a known or valid string name.", lang.getLine(), lang.getName());
break;
}
}
}
//Vector of pointers to slideOutPanels. Is looped and drawn last so they are always on top
std::vector<ui::slideOutPanel *> panels;
void ui::initTheme()
{
@@ -239,6 +68,7 @@ void ui::initTheme()
rectSh = {0xCA, 0xCA, 0xCA, 0xFF};
tboxClr = {0x50, 0x50, 0x50, 0xFF};
divClr = {0x00, 0x00, 0x00, 0xFF};
slidePanelColor = {0xEE, 0xEE, 0xEE, 0xDD};
break;
default:
@@ -253,6 +83,7 @@ void ui::initTheme()
rectSh = {0x20, 0x20, 0x20, 0xFF};
tboxClr = {0xEB, 0xEB, 0xEB, 0xFF};
divClr = {0xFF, 0xFF, 0xFF, 0xFF};
slidePanelColor = {0x2F, 0x2F, 0x2F, 0xDD};
break;
}
}
@@ -263,6 +94,12 @@ void ui::init()
mnuTopRight = gfx::loadImageFile("romfs:/img/fb/menuTopRight.png");
mnuBotLeft = gfx::loadImageFile("romfs:/img/fb/menuBotLeft.png");
mnuBotRight = gfx::loadImageFile("romfs:/img/fb/menuBotRight.png");
leftPanel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET | SDL_TEXTUREACCESS_STATIC, 200, 559);
rightPanel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET | SDL_TEXTUREACCESS_STATIC, 1080, 559);
SDL_SetTextureBlendMode(leftPanel, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(rightPanel, SDL_BLENDMODE_BLEND);
switch(ui::thmID)
{
case ColorSetId_Light:
@@ -290,17 +127,6 @@ void ui::init()
break;
}
if(ui::textMode && data::skipUser)
{
ui::textTitlePrep(data::curUser);
mstate = TXT_TTL;
}
else if(ui::textMode)
mstate = TXT_USR;
else if(data::skipUser)
mstate = TTL_SEL;
textUserPrep();
loadTrans();
//Replace the button [x] in strings that need it. Needs to be outside loadTrans so even defaults will get replaced
@@ -310,9 +136,6 @@ void ui::init()
util::replaceButtonsInString(ui::optHelp);
util::replaceButtonsInString(ui::yt);
util::replaceButtonsInString(ui::nt);
util::replaceButtonsInString(ui::optMenuExp[3]);
util::replaceButtonsInString(ui::optMenuExp[4]);
util::replaceButtonsInString(ui::optMenuExp[5]);
//Calculate x position of help text
userHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18);
@@ -324,13 +147,20 @@ void ui::init()
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
padInitializeDefault(&ui::pad);
advCopyMenuPrep();
ui::exMenuPrep();
ui::optMenuInit();
//Setup touch
hidInitializeTouchScreen();
//advCopyMenuPrep();
ui::usrInit();
ui::ttlInit();
}
void ui::exit()
{
ui::usrExit();
ui::ttlExit();
ui::fldExit();
SDL_DestroyTexture(cornerTopLeft);
SDL_DestroyTexture(cornerTopRight);
SDL_DestroyTexture(cornerBottomLeft);
@@ -343,158 +173,117 @@ void ui::exit()
SDL_DestroyTexture(mnuBotLeft);
SDL_DestroyTexture(mnuBotRight);
SDL_DestroyTexture(leftPanel);
SDL_DestroyTexture(rightPanel);
SDL_DestroyTexture(icn);
}
void ui::addPanel(slideOutPanel *sop)
{
panels.push_back(sop);
}
void ui::showLoadScreen()
{
SDL_Texture *icon = gfx::loadImageFile("romfs:/icon.png");
gfx::clear(&ui::clearClr);
gfx::texDraw(icon, 512, 226);
gfx::drawTextf(18, 1100, 673, &ui::txtCont, "Loading...");
gfx::clearTarget(NULL, &ui::clearClr);
gfx::texDraw(NULL, icon, 512, 232);
gfx::drawTextf(NULL, 16, 1100, 673, &ui::txtCont, "Loading...");
gfx::present();
SDL_DestroyTexture(icon);
}
void ui::drawUI()
{
gfx::clear(&ui::clearClr);
gfx::texDraw(icn, 66, 27);
gfx::drawTextf(24, 130, 38, &ui::txtCont, "JKSV");
gfx::drawLine(&divClr, 30, 88, 1250, 88);
gfx::drawLine(&divClr, 30, 648, 1250, 648);
gfx::clearTarget(NULL, &ui::clearClr);
gfx::clearTarget(leftPanel, &transparent);
gfx::clearTarget(rightPanel, &transparent);
gfx::drawLine(NULL, &divClr, 30, 88, 1250, 88);
gfx::drawLine(NULL, &divClr, 30, 648, 1250, 648);
gfx::texDraw(NULL, icn, 66, 27);
gfx::drawTextf(NULL, 24, 130, 38, &ui::txtCont, "JKSV");
//Version / translation author
gfx::drawTextf(12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR);
gfx::drawTextf(NULL, 12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR);
if(author != "NULL")
gfx::drawTextf(12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str());
gfx::drawTextf(NULL, 12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str());
switch(mstate)
gfx::texDraw(leftPanel, sideBar, 0, 89);
ui::usrDraw(leftPanel);
ui::ttlDraw(rightPanel);
gfx::texDraw(NULL, rightPanel, 200, 89);
gfx::texDraw(NULL, leftPanel, 0, 89);
ui::fldDraw();
for(slideOutPanel *s : panels)
s->draw(&ui::slidePanelColor);
}
static bool debugDisp = false;
bool ui::runApp()
{
ui::updateInput();
uint64_t down = ui::padKeysDown();
if(down & HidNpadButton_StickL && down & HidNpadButton_StickR)
debugDisp = true;
else if(down & HidNpadButton_Plus)
return false;
switch(ui::mstate)
{
case USR_SEL:
gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str());
ui::drawUserMenu();
usrUpdate();
break;
case TTL_SEL:
gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str());
ui::drawTitleMenu();
ttlUpdate();
break;
case FLD_SEL:
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str());
ui::drawFolderMenu();
break;
case TXT_USR:
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str());
ui::drawTextUserMenu();
break;
case TXT_TTL:
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str());
ui::drawTextTitleMenu();
break;
case TXT_FLD:
gfx::texDraw(sideBar, 0, 89);
gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str());
ui::drawTextFolderMenu();
break;
case EX_MNU:
gfx::texDraw(sideBar, 0, 89);
ui::drawExMenu();
fldUpdate();
break;
case OPT_MNU:
gfx::texDraw(sideBar, 0, 89);
ui::drawOptMenu();
break;
case ADV_MDE:
gfx::drawRect(&ui::txtCont, 640, 88, 1, 559);
drawAdvMode();
break;
}
}
void ui::drawBoundBox(int x, int y, int w, int h, int clrSh)
{
SDL_Color rectClr;
if(ui::thmID == ColorSetId_Light)
rectClr = {0xFD, 0xFD, 0xFD, 0xFF};
else
rectClr = {0x21, 0x22, 0x21, 0xFF};
gfx::drawRect(&rectClr, x + 4, y + 4, w - 8, h - 8);
rectClr = {0x00,(uint8_t)(0x88 + clrSh), (uint8_t)(0xC5 + (clrSh / 2)), 0xFF};
SDL_SetTextureColorMod(mnuTopLeft, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuTopRight, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuBotLeft, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuBotRight, rectClr.r, rectClr.g, rectClr.b);
//top
gfx::texDraw(mnuTopLeft, x, y);
gfx::drawRect(&rectClr, x + 4, y, w - 8, 4);
gfx::texDraw(mnuTopRight, (x + w) - 4, y);
//mid
gfx::drawRect(&rectClr, x, y + 4, 4, h - 8);
gfx::drawRect(&rectClr, (x + w) - 4, y + 4, 4, h - 8);
//bottom
gfx::texDraw(mnuBotLeft, x, (y + h) - 4);
gfx::drawRect(&rectClr, x + 4, (y + h) - 4, w - 8, 4);
gfx::texDraw(mnuBotRight, (x + w) - 4, (y + h) - 4);
}
void ui::runApp(const uint64_t& down, const uint64_t& held)
{
switch(mstate)
{
case USR_SEL:
updateUserMenu(down, held);
break;
case TTL_SEL:
updateTitleMenu(down, held);
break;
case FLD_SEL:
updateFolderMenu(down, held);
break;
case ADV_MDE:
updateAdvMode(down, held);
break;
case TXT_USR:
textUserMenuUpdate(down, held);
break;
case TXT_TTL:
textTitleMenuUpdate(down, held);
break;
case TXT_FLD:
textFolderMenuUpdate(down, held);
/*optMenu.update();
if(down & HidNpadButton_B)
{
ui::changeState(USR_SEL);
mainMenu.setActive(true);
optMenu.setActive(false);
}*/
break;
case EX_MNU:
updateExMenu(down, held);
break;
case OPT_MNU:
updateOptMenu(down, held);
/*extMenu.update();
if(down & HidNpadButton_B)
{
ui::changeState(USR_SEL);
mainMenu.setActive(true);
extMenu.setActive(false);
}*/
break;
}
drawUI();
drawPopup(down);
drawPopup(ui::padKeysDown());
if(debugDisp)
data::dispStats();
gfx::present();
return true;
}
void ui::toTTL(void *a)
{
if(data::curUser.titleInfo.size() > 0)
{
ui::changeState(TTL_SEL);
ui::usrMenuSetActive(false);
}
else
ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str());
}

View File

@@ -2,11 +2,10 @@
#include <vector>
#include <sys/stat.h>
#include "file.h"
#include "ui.h"
#include "miscui.h"
#include "uiupdate.h"
#include "util.h"
#include "file.h"
//Text menus
static ui::menu saveMenu, sdMenu, copyMenu;
@@ -342,20 +341,20 @@ void performCopyMenuOps()
}
void ui::advCopyMenuPrep()
void advCopyMenuPrep()
{
for(unsigned i = 0; i < 6; i++)
copyMenu.addOpt(ui::advMenuStr[i]);
copyMenu.addOpt(NULL, ui::advMenuStr[i]);
}
void ui::advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite)
void advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite)
{
commit = commitOnWrite;
type = _type;
saveMenu.setParams(30, 98, 602);
sdMenu.setParams(648, 98, 602);
copyMenu.setParams(472, 278, 304);
saveMenu.setParams(30, 98, 602, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT);
sdMenu.setParams(648, 98, 602, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT);
copyMenu.setParams(472, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT);
savePath = svDev, dev = svDev;
sdPath = "sdmc:/";
@@ -369,13 +368,13 @@ void ui::advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool
advMenuCtrl = 0;
}
void ui::drawAdvMode()
void drawAdvMode()
{
saveMenu.draw(&ui::txtCont);
sdMenu.draw(&ui::txtCont);
saveMenu.draw(NULL, &ui::txtCont, true);
sdMenu.draw(NULL, &ui::txtCont, true);
gfx::drawTextfWrap(14, 30, 654, 600, &ui::txtCont, savePath.c_str());
gfx::drawTextfWrap(14, 640, 654, 600, &ui::txtCont, sdPath.c_str());
gfx::drawTextfWrap(NULL, 14, 30, 654, 600, &ui::txtCont, savePath.c_str());
gfx::drawTextfWrap(NULL, 14, 640, 654, 600, &ui::txtCont, sdPath.c_str());
//draw copy menu if it's supposed to be up
if(advMenuCtrl == 2)
@@ -383,38 +382,38 @@ void ui::drawAdvMode()
switch(advPrev)
{
case 0:
copyMenu.setParams(176, 278, 304);
copyMenu.editOpt(0, advMenuStr[0] + "sdmc");
ui::drawTextbox(168, 236, 320, 268);
gfx::drawTextf(18, 176, 250, &ui::txtDiag, dev.c_str());
copyMenu.setParams(176, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT);
copyMenu.editOpt(0, NULL, ui::advMenuStr[0] + "sdmc");
ui::drawTextbox(NULL, 168, 236, 320, 268);
gfx::drawTextf(NULL, 18, 176, 250, &ui::txtDiag, dev.c_str());
break;
case 1:
copyMenu.setParams(816, 278, 304);
copyMenu.editOpt(0, advMenuStr[0] + dev);
ui::drawTextbox(808, 236, 320, 268);
gfx::drawTextf(18, 816, 250, &ui::txtDiag, "SDMC");
copyMenu.setParams(816, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT);
copyMenu.editOpt(0, NULL, ui::advMenuStr[0] + dev);
ui::drawTextbox(NULL, 808, 236, 320, 268);
gfx::drawTextf(NULL, 18, 816, 250, &ui::txtDiag, "SDMC");
break;
}
copyMenu.draw(&ui::txtDiag);
copyMenu.draw(NULL, &ui::txtDiag, true);
}
}
void ui::updateAdvMode(const uint64_t& down, const uint64_t& held)
void updateAdvMode(const uint64_t& down, const uint64_t& held)
{
//0 = save; 1 = sd; 2 = cpy
switch(advMenuCtrl)
{
case 0:
saveMenu.handleInput(down, held);
saveMenu.update();
break;
case 1:
sdMenu.handleInput(down, held);
sdMenu.update();
break;
case 2:
copyMenu.handleInput(down, held);
copyMenu.update();
break;
}
@@ -511,18 +510,18 @@ void ui::updateAdvMode(const uint64_t& down, const uint64_t& held)
}
else if(down & HidNpadButton_Minus)
{
switch(prevState)
switch(ui::prevState)
{
case EX_MNU:
mstate = EX_MNU;
ui::mstate = EX_MNU;
break;
case TTL_SEL:
mstate = TTL_SEL;
ui::mstate = TTL_SEL;
break;
default:
mstate = ui::textMode ? TXT_FLD : FLD_SEL;
ui::mstate = ui::textMode ? TXT_FLD : FLD_SEL;
break;
}
}

82
src/ui/fld.cpp Normal file
View File

@@ -0,0 +1,82 @@
#include "fld.h"
#include "ui.h"
#include "file.h"
#include "data.h"
#include "util.h"
static ui::slideOutPanel *fldSlide = NULL;
static ui::menu fldMenu;
static fs::dirList fldList;
static fs::backupArgs backargs;
static void fldCallback(void *a)
{
if(ui::padKeysDown() & HidNpadButton_B)
{
fs::unmountSave();
fldSlide->closePanel();
ui::changeState(TTL_SEL);
}
}
static void slideDrawFunc(void *a)
{
//Slide panel passes texture/target to draw func
SDL_Texture *panel = (SDL_Texture *)a;
fldMenu.draw(panel, &ui::txtCont, true);
}
void ui::fldInit()
{
//Only allocate new if null
if(!fldSlide)
{
fldSlide = new ui::slideOutPanel(410, 720, 0, slideDrawFunc);
ui::addPanel(fldSlide);
}
fldMenu.reset();
fldMenu.setParams(12, 32, 390, MENU_FONT_SIZE_DEFAULT, 8);
fldMenu.setCallback(fldCallback, NULL);
util::createTitleDirectoryByTID(data::curUser.titleInfo[data::selData].saveID);
std::string folderPath = util::generatePathByTID(data::curUser.titleInfo[data::selData].saveID);
fldList.reassign(folderPath);
fs::loadPathFilters(folderPath + "pathFilters.txt");
backargs = {&fldMenu, &fldList};
fldMenu.addOpt(NULL, "New");
fldMenu.setOptFunc(0, FUNC_A, fs::createNewBackup, &backargs);
//Same as above, args updated at press
for(unsigned i = 0; i < fldList.getCount(); i++)
{
fldMenu.addOpt(NULL, fldList.getItem(i));
//Pass the menu to the functions so selected can be grabbed
//offset i by 1 since new is always first option
fldMenu.setOptFunc(i + 1, FUNC_A, fs::overwriteBackup, &backargs);
fldMenu.setOptFunc(i + 1, FUNC_X, fs::deleteBackup, &backargs);
fldMenu.setOptFunc(i + 1, FUNC_Y, fs::restoreBackup, &backargs);
}
fldSlide->openPanel();
}
void ui::fldExit()
{
if(fldSlide)
delete fldSlide;
}
void ui::fldUpdate()
{
fldMenu.update();
}
void ui::fldDraw()
{
/*if(fldSlide)
fldSlide->draw(&slidePanelColor);*/
}

View File

@@ -1,227 +0,0 @@
#include <string>
#include <vector>
#include <sys/stat.h>
#include "ui.h"
#include "uiupdate.h"
#include "util.h"
ui::menu folderMenu;
static fs::dirList fldList;
void ui::folderMenuPrepare(data::user& usr, data::titledata& dat)
{
folderMenu.setParams(466, 98, 730);
folderMenu.reset();
dat.createDir();
fldList.reassign(dat.getPath());
fs::loadPathFilters(dat.getPath() + "pathFilters.txt");
folderMenu.addOpt("New");
for(unsigned i = 0; i < fldList.getCount(); i++)
folderMenu.addOpt(fldList.getItem(i));
folderMenu.adjust();
}
void ui::createNewBackup(const uint64_t& held)
{
std::string out;
if(held & HidNpadButton_R)
out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
else if(held & HidNpadButton_L)
out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM);
else if(held & HidNpadButton_ZL)
out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE);
else
{
const std::string dict[] =
{
util::getDateTime(util::DATE_FMT_YMD),
util::getDateTime(util::DATE_FMT_YDM),
util::getDateTime(util::DATE_FMT_HOYSTE),
util::getDateTime(util::DATE_FMT_JHK),
util::getDateTime(util::DATE_FMT_ASC),
data::curUser.getUsernameSafe(),
data::curData.getTitleSafe(),
util::generateAbbrev(data::curData)
};
out = util::getStringInput("", "Enter a name", 64, 8, dict);
}
if(!out.empty())
{
std::string path = data::curData.getPath() + "/" + out;
switch(data::zip)
{
case true:
{
path += ".zip";
zipFile zip = zipOpen(path.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
break;
case false:
{
mkdir(path.c_str(), 777);
path += "/";
fs::copyDirToDir("sv:/", path);
}
break;
}
folderMenuPrepare(data::curUser, data::curData);
}
}
void ui::overwriteBackup(unsigned ind)
{
std::string itemName = fldList.getItem(ind);
if(confirm(data::holdOver, ui::confOverwrite.c_str(), itemName.c_str()))
{
if(fldList.isDir(ind))
{
std::string toPath = data::curData.getPath() + itemName + "/";
//Delete and recreate
fs::delDir(toPath);
mkdir(toPath.c_str(), 777);
fs::copyDirToDir("sv:/", toPath);
}
else if(!fldList.isDir(ind) && fldList.getItemExt(ind) == "zip")
{
std::string toPath = data::curData.getPath() + itemName;
fs::delfile(toPath);
zipFile zip = zipOpen(toPath.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
}
}
void ui::restoreBackup(unsigned ind)
{
std::string itemName = fldList.getItem(ind);
if((data::curData.getType() != FsSaveDataType_System || data::sysSaveWrite) && folderMenu.getSelected() > 0 && confirm(data::holdRest, ui::confRestore.c_str(), itemName.c_str()))
{
if(data::autoBack)
{
switch(data::zip)
{
case true:
{
std::string autoZip = data::curData.getPath() + "/AUTO " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen(autoZip.c_str(), 0);
fs::copyDirToZip("sv:/", &zip);
zipClose(zip, NULL);
}
break;
case false:
{
std::string autoFolder = data::curData.getPath() + "/AUTO - " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
mkdir(autoFolder.substr(0, autoFolder.length() - 1).c_str(), 777);
fs::copyDirToDir("sv:/", autoFolder);
}
break;
}
}
if(fldList.isDir(ind))
{
fs::wipeSave();
std::string fromPath = data::curData.getPath() + itemName + "/";
fs::copyDirToDirCommit(fromPath, "sv:/", "sv");
}
else if(!fldList.isDir(ind) && fldList.getItemExt(ind) == "zip")
{
fs::wipeSave();
std::string path = data::curData.getPath() + itemName;
unzFile unz = unzOpen(path.c_str());
fs::copyZipToDir(&unz, "sv:/", "sv");
unzClose(unz);
}
else
{
//Just copy file over
std::string fromPath = data::curData.getPath() + itemName;
std::string toPath = "sv:/" + itemName;
fs::copyFileCommit(fromPath, toPath, "sv");
}
}
if(data::autoBack)
folderMenuPrepare(data::curUser, data::curData);
}
void ui::deleteBackup(unsigned ind)
{
std::string itemName = fldList.getItem(folderMenu.getSelected() - 1);
if(ui::confirmDelete(itemName))
{
if(fldList.isDir(ind))
{
std::string delPath = data::curData.getPath() + itemName + "/";
fs::delDir(delPath);
}
else
{
std::string delPath = data::curData.getPath() + itemName;
fs::delfile(delPath);
}
}
folderMenuPrepare(data::curUser, data::curData);
}
void ui::drawFolderMenu()
{
data::curData.drawIcon(true, 96, 98);
gfx::drawTextfWrap(16, 60, 370, 360, &ui::txtCont, folderMenuInfo.c_str());
folderMenu.draw(&ui::txtCont);
}
void ui::updateFolderMenu(const uint64_t& down, const uint64_t& held)
{
folderMenu.handleInput(down, held);
switch(down)
{
case HidNpadButton_A:
if(folderMenu.getSelected() == 0)
ui::createNewBackup(held);
else
ui::overwriteBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_B:
fs::unmountSave();
fs::freePathFilters();
ui::changeState(TTL_SEL);
break;
case HidNpadButton_X:
if(folderMenu.getSelected() > 0)
ui::deleteBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_Y:
if(folderMenu.getSelected() > 0)
ui::restoreBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_ZR:
if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseFolder.c_str(), data::curData.getTitle().c_str()))
{
fs::delDir("sv:/");
fsdevCommitDevice("sv");
}
break;
case HidNpadButton_Minus:
advModePrep("sv:/", data::curData.getType(), true);
ui::changeState(ADV_MDE);
break;
}
}

View File

@@ -1,162 +0,0 @@
#include <string>
#include <switch.h>
#include "gfx.h"
#include "menu.h"
#include "ui.h"
#include "miscui.h"
static const SDL_Color menuColorLight = {0x32, 0x50, 0xF0, 0xFF};
static const SDL_Color menuColorDark = {0x00, 0xFF, 0xC5, 0xFF};
#define HOLD_FC 10
void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW)
{
x = _x;
y = _y;
rW = _rW;
rY = _y;
}
void ui::menu::addOpt(const std::string& add)
{
if(gfx::getTextWidth(add.c_str(), 18) < rW - 32 || rW == 0)
opt.push_back(add);
else
{
std::string tmp;
for(unsigned i = 0; i < add.length(); )
{
uint32_t tmpChr = 0;
ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&add.c_str()[i]);
tmp += add.substr(i, untCnt);
i += untCnt;
if(gfx::getTextWidth(tmp.c_str(), 18) >= rW - 32)
{
opt.push_back(tmp);
break;
}
}
}
}
void ui::menu::editOpt(int ind, const std::string& ch)
{
opt[ind] = ch;
}
ui::menu::~menu()
{
opt.clear();
}
void ui::menu::handleInput(const uint64_t& down, const uint64_t& held)
{
if( (held & HidNpadButton_Up) || (held & HidNpadButton_Down))
fc++;
else
fc = 0;
if(fc > 10)
fc = 0;
int size = opt.size() - 1;
if((down & HidNpadButton_Up) || ((held & HidNpadButton_Up) && fc == HOLD_FC))
{
selected--;
if(selected < 0)
selected = size;
if((start > selected) && (start > 0))
start--;
if(size < 15)
start = 0;
if((selected - 14) > start)
start = selected - 14;
}
else if((down & HidNpadButton_Down) || ((held & HidNpadButton_Down) && fc == HOLD_FC))
{
selected++;
if(selected > size)
selected = 0;
if((selected > (start + 14)) && ((start + 14) < size))
start++;
if(selected == 0)
start = 0;
}
else if(down & HidNpadButton_Right)
{
selected += 7;
if(selected > size)
selected = size;
if((selected - 14) > start)
start = selected - 14;
}
else if(down & HidNpadButton_Left)
{
selected -= 7;
if(selected < 0)
selected = 0;
if(selected < start)
start = selected;
}
}
void ui::menu::draw(const SDL_Color *textClr)
{
if(opt.size() < 1)
return;
if(clrAdd)
{
clrSh += 6;
if(clrSh >= 0x72)
clrAdd = false;
}
else
{
clrSh -= 3;
if(clrSh <= 0x00)
clrAdd = true;
}
int length = 0;
if((opt.size() - 1) < 15)
length = opt.size();
else
length = start + 15;
for(int i = start; i < length; i++)
{
if(i == selected)
{
ui::drawBoundBox(x, y + ((i - start) * 36), rW, 36, clrSh);
gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].c_str());
}
else
gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), textClr, opt[i].c_str());
}
}
void ui::menu::reset()
{
opt.clear();
start = 0;
selected = 0;
fc = 0;
}
void ui::menu::adjust()
{
if(selected > (int)opt.size() - 1)
selected = opt.size() - 1;
if(opt.size() < 14)
start = 0;
else if(opt.size() > 14 && start + 14 > (int)opt.size() - 1)
start = opt.size() - 15;
}

View File

@@ -20,6 +20,9 @@ static const SDL_Color fillBack = {0x66, 0x66, 0x66, 0xFF};
static const SDL_Color fillLight = {0x00, 0xFF, 0xC5, 0xFF};
static const SDL_Color fillDark = {0x32, 0x50, 0xF0, 0xFF};
static const SDL_Color menuColorLight = {0x32, 0x50, 0xF0, 0xFF};
static const SDL_Color menuColorDark = {0x00, 0xFF, 0xC5, 0xFF};
enum popStates
{
popRise,
@@ -27,11 +30,264 @@ enum popStates
popFall
};
//8
static const std::string loadGlyphArray[] =
{
"\ue020", "\ue021", "\ue022", "\ue023",
"\ue024", "\ue025", "\ue026", "\ue027"
};
void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW, const unsigned& _fS, const unsigned& _mL)
{
x = _x;
y = _y;
rW = _rW;
rY = _y;
fSize = _fS;
mL = _mL;
rH = _fS + 24;
}
void ui::menu::editParam(int _param, unsigned newVal)
{
switch(_param)
{
case MENU_X:
x = newVal;
break;
case MENU_Y:
y = newVal;
break;
case MENU_RECT_WIDTH:
rW = newVal;
break;
case MENU_FONT_SIZE:
fSize = newVal;
break;
case MENU_MAX_SCROLL:
mL = newVal;
break;
}
}
void ui::menu::addOpt(SDL_Texture *_icn, const std::string& add)
{
ui::menuOpt newOpt;
if((int)gfx::getTextWidth(add.c_str(), fSize) < rW - 56 || rW == 0)
newOpt.txt = add;
else
{
std::string tmp;
for(unsigned i = 0; i < add.length(); )
{
uint32_t tmpChr = 0;
ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&add.c_str()[i]);
tmp += add.substr(i, untCnt);
i += untCnt;
if((int)gfx::getTextWidth(tmp.c_str(), fSize) >= rW - 48)
{
newOpt.txt = tmp;
break;
}
}
}
newOpt.icn = _icn;
opt.push_back(newOpt);
}
void ui::menu::editOpt(int ind, SDL_Texture *_icn, const std::string& ch)
{
if(!opt[ind].icn && _icn)
opt[ind].icn = _icn;
opt[ind].txt = ch;
}
void ui::menu::setOptFunc(unsigned _ind, unsigned _funcbtn, funcPtr _func, void *args)
{
opt[_ind].func[_funcbtn] = _func;
opt[_ind].argPtr[_funcbtn] = args;
}
int ui::menu::getOptPos(const std::string& txt)
{
for(unsigned i = 0; i < opt.size(); i++)
{
if(opt[i].txt == txt)
return i;
}
return -1;
}
ui::menu::~menu()
{
opt.clear();
}
void ui::menu::update()
{
if(!isActive)
return;
uint64_t down = ui::padKeysDown();
uint64_t held = ui::padKeysHeld();
if(held & HidNpadButton_AnyUp || held & HidNpadButton_AnyDown)
++fc;
else
fc = 0;
if(fc > 10)
fc = 0;
int oldSel = selected;
int mSize = opt.size() - 1, scrL = mL - 1;
if( (down & HidNpadButton_AnyUp) || ((held & HidNpadButton_AnyUp) && fc == 10) )
{
--selected;
if(selected < 0)
selected = mSize;
if(mSize > (int)mL)
{
if(start > selected)
--start;
else if(selected - scrL > start)
start = selected - scrL;
}
}
else if( (down & HidNpadButton_AnyDown) || ((held & HidNpadButton_AnyDown) && fc == 10))
{
++selected;
if(selected > mSize)
selected = 0;
if(selected > (start + scrL) && (start + scrL) < mSize)
++start;
if(selected == 0)
start = 0;
}
else if(down & HidNpadButton_AnyLeft)
{
selected -= scrL / 2;
if(selected < 0)
selected = 0;
if(selected < start)
start = selected;
}
else if(down & HidNpadButton_AnyRight)
{
selected += scrL / 2;
if(selected > mSize)
selected = mSize;
if(selected - scrL > start)
start = selected - scrL;
}
//func exec
switch(down)
{
case HidNpadButton_A:
if(opt[selected].func[FUNC_A])
(*opt[selected].func[FUNC_A])(opt[selected].argPtr[FUNC_A]);
break;
case HidNpadButton_B:
if(opt[selected].func[FUNC_B])
(*opt[selected].func[FUNC_B])(opt[selected].argPtr[FUNC_B]);
break;
case HidNpadButton_X:
if(opt[selected].func[FUNC_X])
(*opt[selected].func[FUNC_X])(opt[selected].argPtr[FUNC_X]);
break;
case HidNpadButton_Y:
if(opt[selected].func[FUNC_Y])
(*opt[selected].func[FUNC_Y])(opt[selected].argPtr[FUNC_Y]);
break;
}
if(selected != oldSel && onChange)
(*onChange)(NULL);
if(callback)
(*callback)(callbackArgs);
}
void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText)
{
if(opt.size() < 1)
return;
if(clrAdd)
{
clrSh += 6;
if(clrSh >= 0x72)
clrAdd = false;
}
else
{
clrSh -= 3;
if(clrSh <= 0x00)
clrAdd = true;
}
for(int i = start; i < (int)opt.size(); i++)
{
if(i == selected)
{
if(isActive)
ui::drawBoundBox(target, x, y + ((i - start) * rH), rW, rH, clrSh);
gfx::drawRect(target, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, x + 10, ((y + (rH / 2 - fSize / 2)) + ((i - start) * rH)) - 2, 4, fSize + 4);
if(drawText)
gfx::drawTextf(target, fSize, x + 20, (y + (rH / 2 - fSize / 2)) + ((i - start) * rH), ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].txt.c_str());
}
else
{
if(drawText)
gfx::drawTextf(target, fSize, x + 20, (y + (rH / 2 - fSize / 2)) + ((i - start) * rH), textClr, opt[i].txt.c_str());
}
int w, h;
if(opt[i].icn && SDL_QueryTexture(opt[i].icn, NULL, NULL, &w, &h) == 0)
{
float scale = (float)fSize / (float)h;
int dW = scale * w;
int dH = scale * h;
gfx::texDrawStretch(target, opt[i].icn, x + 20, (y + (rH / 2 - fSize / 2)) + ((i - start) * rH), dW, dH);
}
}
}
void ui::menu::reset()
{
opt.clear();
start = 0;
selected = 0;
fc = 0;
}
void ui::menu::setActive(bool _set)
{
isActive = _set;
}
void ui::progBar::update(const uint64_t& _prog)
{
prog = _prog;
width = (float)(((float)prog / (float)max) * (float)maxWidth);
width = (float)(((float)prog / (float)max) * 576);
}
void ui::progBar::draw(const std::string& text, const std::string& head)
@@ -39,24 +295,55 @@ void ui::progBar::draw(const std::string& text, const std::string& head)
size_t headWidth = gfx::getTextWidth(head.c_str(), 20);
unsigned headX = (1280 / 2) - (headWidth / 2);
ui::drawTextbox(320, 150, 640, 420);
gfx::drawLine(ui::thmID == ColorSetId_Light ? &divLight : &divDark, 320, 206, 959, 206);
gfx::drawRect(&fillBack, 352, 530, 576, 12);
gfx::drawRect(ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, 352, 530, (int)width, 12);
gfx::texDraw(ui::progCovLeft, 352, 530);
gfx::texDraw(ui::progCovRight, 920, 530);
ui::drawTextbox(NULL, 320, 150, 640, 420);
gfx::drawLine(NULL, ui::thmID == ColorSetId_Light ? &divLight : &divDark, 320, 206, 959, 206);
gfx::drawRect(NULL, &fillBack, 352, 530, 576, 12);
gfx::drawRect(NULL, ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, 352, 530, (int)width, 12);
gfx::texDraw(NULL, ui::progCovLeft, 352, 530);
gfx::texDraw(NULL, ui::progCovRight, 920, 530);
gfx::drawTextf(20, headX, 160, &ui::txtDiag, head.c_str());
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, text.c_str());
gfx::drawTextf(NULL, 20, headX, 168, &ui::txtDiag, head.c_str());
gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, text.c_str());
}
void ui::progBar::drawNoDialog(int x, int y)
ui::slideOutPanel::slideOutPanel(int _w, int _h, int _y, funcPtr _draw)
{
gfx::drawRect(&fillBack, x, y, maxWidth, 12);
gfx::drawRect(ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, x, y, width, 12);
gfx::texDraw(ui::progCovLeft, x, y);
gfx::texDraw(ui::progCovRight, x + maxWidth - 8, y);
w = _w;
h = _h;
y = _y;
drawFunc = _draw;
panel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, w, h);
SDL_SetTextureBlendMode(panel, SDL_BLENDMODE_BLEND);
int getDiv = 99;
while(w % getDiv != 0){ getDiv--; }
slideSpd = getDiv;
}
ui::slideOutPanel::~slideOutPanel()
{
SDL_DestroyTexture(panel);
}
void ui::slideOutPanel::draw(const SDL_Color *backCol)
{
gfx::clearTarget(panel, backCol);
if(open && x > 1280 - w)
{
x -= slideSpd;
}
else if(!open && x < 1280)
{
x += slideSpd;
}
//don't waste time drawing if you can't even see it.
if(x < 1280)
{
(*drawFunc)(panel);
gfx::texDraw(NULL, panel, x, y);
}
}
void ui::showMessage(const char *head, const char *fmt, ...)
@@ -72,17 +359,18 @@ void ui::showMessage(const char *head, const char *fmt, ...)
while(true)
{
ui::updatePad();
ui::updateInput();
if(ui::padKeysDown())
break;
ui::drawTextbox(320, 150, 640, 420);
gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, head);
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp);
gfx::drawTextf(20, 320 + okX, 522, &ui::txtDiag, okt);
ui::drawTextbox(NULL, 320, 150, 640, 420);
gfx::drawTextf(NULL, 20, 320 + headX, 168, &ui::txtDiag, head);
gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, tmp);
gfx::drawTextf(NULL, 20, 320 + okX, 522, &ui::txtDiag, okt);
gfx::present();
}
ui::updateInput();
}
bool ui::confirm(bool hold, const char *fmt, ...)
@@ -106,7 +394,7 @@ bool ui::confirm(bool hold, const char *fmt, ...)
while(true)
{
ui::updatePad();
ui::updateInput();
uint64_t down = ui::padKeysDown();
uint64_t held = ui::padKeysHeld();
@@ -161,18 +449,21 @@ bool ui::confirm(bool hold, const char *fmt, ...)
if(hold && heldDown)
{
if(ui::thmID == ColorSetId_Light)
holdClr = {0xFF, 0xFF - holdClrDiff, 0xFF - holdClrDiff, 0xFF};
holdClr = {0xFF, (uint8_t)(0xFF - holdClrDiff), (uint8_t)(0xFF - holdClrDiff), 0xFF};
else
holdClr = {0x25 + holdClrDiff, 0x00, 0x00, 0xFF};
holdClr = {(uint8_t)(0x25 + holdClrDiff), 0x00, 0x00, 0xFF};
}
ui::drawTextbox(320, 150, 640, 420);
gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, ui::confirmHead.c_str());
gfx::drawTextf(20, 320 + yesX, 522, &holdClr, yesText.c_str());
gfx::drawTextf(20, 640 + noX, 522, &ui::txtDiag, ui::nt.c_str());
gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp);
ui::drawTextbox(NULL, 320, 150, 640, 420);
gfx::drawTextf(NULL, 20, 320 + headX, 168, &ui::txtDiag, ui::confirmHead.c_str());
gfx::drawTextf(NULL, 20, 320 + yesX, 522, &holdClr, yesText.c_str());
gfx::drawTextf(NULL, 20, 640 + noX, 522, &ui::txtDiag, ui::nt.c_str());
gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, tmp);
gfx::present();
}
ui::updateInput();
return ret;
}
@@ -186,40 +477,55 @@ bool ui::confirmDelete(const std::string& p)
return confirm(data::holdDel, ui::confDel.c_str(), p.c_str());
}
void ui::drawTextbox(int x, int y, int w, int h)
void ui::drawTextbox(SDL_Texture *target, int x, int y, int w, int h)
{
//Top
gfx::texDraw(ui::cornerTopLeft, x, y);
gfx::drawRect(&ui::tboxClr, x + 32, y, w - 64, 32);
gfx::texDraw(ui::cornerTopRight, (x + w) - 32, y);
gfx::texDraw(target, ui::cornerTopLeft, x, y);
gfx::drawRect(target, &ui::tboxClr, x + 32, y, w - 64, 32);
gfx::texDraw(target, ui::cornerTopRight, (x + w) - 32, y);
//middle
gfx::drawRect(&ui::tboxClr, x, y + 32, w, h - 64);
gfx::drawRect(target, &ui::tboxClr, x, y + 32, w, h - 64);
//bottom
gfx::texDraw(ui::cornerBottomLeft, x, (y + h) - 32);
gfx::drawRect(&ui::tboxClr, x + 32, (y + h) - 32, w - 64, 32);
gfx::texDraw(ui::cornerBottomRight, (x + w) - 32, (y + h) - 32);
gfx::texDraw(target, ui::cornerBottomLeft, x, (y + h) - 32);
gfx::drawRect(target, &ui::tboxClr, x + 32, (y + h) - 32, w - 64, 32);
gfx::texDraw(target, ui::cornerBottomRight, (x + w) - 32, (y + h) - 32);
}
/*void ui::drawTextboxInvert(tex *target, int x, int y, int w, int h)
void ui::drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh)
{
clr temp = ui::tboxClr;
clrInvert(&temp);
SDL_SetRenderTarget(gfx::render, target);
SDL_Color rectClr;
//Top
texDrawInvert(ui::cornerTopLeft, target, x, y);
drawRect(target, x + 32, y, w - 64, 32, temp);
texDrawInvert(ui::cornerTopRight, target, (x + w) - 32, y);
if(ui::thmID == ColorSetId_Light)
rectClr = {0xFD, 0xFD, 0xFD, 0xFF};
else
rectClr = {0x21, 0x22, 0x21, 0xFF};
//middle
drawRect(target, x, y + 32, w, h - 64, temp);
gfx::drawRect(target, &rectClr, x + 4, y + 4, w - 8, h - 8);
rectClr = {0x00,(uint8_t)(0x88 + clrSh), (uint8_t)(0xC5 + (clrSh / 2)), 0xFF};
SDL_SetTextureColorMod(mnuTopLeft, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuTopRight, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuBotLeft, rectClr.r, rectClr.g, rectClr.b);
SDL_SetTextureColorMod(mnuBotRight, rectClr.r, rectClr.g, rectClr.b);
//top
gfx::texDraw(target, mnuTopLeft, x, y);
gfx::drawRect(target, &rectClr, x + 4, y, w - 8, 4);
gfx::texDraw(target, mnuTopRight, (x + w) - 4, y);
//mid
gfx::drawRect(target, &rectClr, x, y + 4, 4, h - 8);
gfx::drawRect(target, &rectClr, (x + w) - 4, y + 4, 4, h - 8);
//bottom
texDrawInvert(ui::cornerBottomLeft, target, x, (y + h) - 32);
drawRect(target, x + 32, (y + h) - 32, w - 64, 32, temp);
texDrawInvert(ui::cornerBottomRight, target, (x + w) - 32, (y + h) - 32);
}*/
gfx::texDraw(target, mnuBotLeft, x, (y + h) - 4);
gfx::drawRect(target, &rectClr, x + 4, (y + h) - 4, w - 8, 4);
gfx::texDraw(target, mnuBotRight, (x + w) - 4, (y + h) - 4);
}
void ui::showPopup(unsigned frames, const char *fmt, ...)
{
@@ -267,7 +573,7 @@ void ui::drawPopup(const uint64_t& down)
break;
}
drawTextbox(popX, popY, popWidth, 64);
gfx::drawTextf(24, popX + 16, popY + 20, &ui::txtDiag, popText.c_str());
drawTextbox(NULL, popX, popY, popWidth, 64);
gfx::drawTextf(NULL, 24, popX + 16, popY + 20, &ui::txtDiag, popText.c_str());
}

347
src/ui/ttl.cpp Normal file
View File

@@ -0,0 +1,347 @@
#include "ui.h"
#include "ttl.h"
#include "file.h"
#include "util.h"
class titleTile
{
public:
titleTile(unsigned _w, unsigned _h, bool _fav, SDL_Texture *_icon)
{
w = _w;
h = _h;
wS = _w;
hS = _h;
fav = _fav;
icon = _icon;
}
void draw(SDL_Texture *target, int x, int y, bool sel);
private:
unsigned w, h, wS, hS;
bool fav = false;
SDL_Texture *icon;
};
static uint8_t clrShft = 0;
static bool clrAdd = true;
static int selRectX = 38, selRectY = 38;
static int x = 34, y = 69, ttlHelpX = 0;
static std::vector<titleTile> titleList;
static ui::menu *ttlOpts;
static ui::slideOutPanel *ttlOptsPanel, *infoPanel;
static std::string infoPanelString;
static void ttlOptsCallback(void *a)
{
switch(ui::padKeysDown())
{
case HidNpadButton_B:
ttlOpts->setActive(false);
ttlOptsPanel->closePanel();
ui::updateInput();
break;
}
}
static void ttlOptsPanelDraw(void *a)
{
SDL_Texture *panel = (SDL_Texture *)a;
ttlOpts->draw(panel, &ui::txtCont, true);
}
static void ttlOptsShowInfoPanel(void *a)
{
ttlOpts->setActive(false);
ttlOptsPanel->closePanel();
infoPanelString = util::getInfoString(data::curUser, data::curData.saveID);
infoPanel->openPanel();
}
static void ttlOptsBlacklistTitle(void *a)
{
std::string title = data::getTitleNameByTID(data::curData.saveID);
if(ui::confirm(false, ui::confBlacklist.c_str(), title.c_str()))
{
data::blacklistAdd(data::curData.saveID);
ui::setupTiles(NULL);
}
}
static void ttlOptsResetSaveData(void *a)
{
std::string title = data::getTitleNameByTID(data::curData.saveID);
if(ui::confirm(data::holdDel, ui::saveDataReset.c_str(), title.c_str()) && fs::mountSave(data::curData.saveInfo))
{
fs::delDir("sv:/");
fsdevCommitDevice("sv:/");
fs::unmountSave();
ui::showPopup(POP_FRAME_DEFAULT, ui::saveDataResetSuccess.c_str(), title.c_str());
}
}
static void ttlOptsDeleteSaveData(void *a)
{
FsSaveDataAttribute attr;
attr.application_id = data::curData.saveID;
attr.uid = data::curUser.getUID();
attr.system_save_data_id = 0;
attr.save_data_type = data::curData.saveInfo.save_data_type;
attr.save_data_rank = data::curData.saveInfo.save_data_rank;
attr.save_data_index = data::curData.saveInfo.save_data_index;
std::string title = data::getTitleNameByTID(data::curData.saveID);
if(ui::confirm(data::holdDel, ui::confEraseNand.c_str(), title.c_str()) && R_SUCCEEDED(fsDeleteSaveDataFileSystemBySaveDataAttribute(FsSaveDataSpaceId_User, &attr)))
{
data::loadUsersTitles(false);
if(data::curUser.titleInfo.size() == 0)
{
//Kick back to user
ttlOptsPanel->closePanel();//JIC
ui::usrMenuSetActive(true);
ui::changeState(USR_SEL);
}
else if(data::selData > (int)data::curUser.titleInfo.size() - 1)
data::selData = data::curUser.titleInfo.size() - 1;
ui::setupTiles(NULL);
ui::showPopup(POP_FRAME_DEFAULT, ui::saveDataDeleteSuccess.c_str(), title.c_str());
}
}
static void infoPanelDraw(void *a)
{
SDL_Texture *panel = (SDL_Texture *)a;
gfx::texDraw(panel, data::getTitleIconByTID(data::curData.saveID), 77, 32);
gfx::drawTextfWrap(panel, 18, 32, 320, 362, &ui::txtCont, infoPanelString.c_str());
}
void ui::ttlInit()
{
ttlHelpX = 1220 - gfx::getTextWidth(ui::titleHelp.c_str(), 18);
ttlOpts = new ui::menu;
ttlOpts->setParams(10, 32, 390, 18, 8);
ttlOptsPanel = new ui::slideOutPanel(410, 720, 0, ttlOptsPanelDraw);
ttlOpts->setCallback(ttlOptsCallback, NULL);
ui::addPanel(ttlOptsPanel);
infoPanel = new ui::slideOutPanel(410, 720, 0, infoPanelDraw);
ui::addPanel(infoPanel);
ttlOpts->setActive(false);
ttlOpts->addOpt(NULL, ui::titleOptString[0]);
ttlOpts->setOptFunc(0, FUNC_A, ttlOptsShowInfoPanel, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[1]);
ttlOpts->setOptFunc(1, FUNC_A, ttlOptsBlacklistTitle, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[2]);
ttlOpts->setOptFunc(2, FUNC_A, ttlOptsResetSaveData, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[3]);
ttlOpts->setOptFunc(3, FUNC_A, ttlOptsDeleteSaveData, NULL);
}
void ui::ttlExit()
{
delete ttlOptsPanel;
delete ttlOpts;
delete infoPanel;
}
void ui::setupTiles(void *)
{
titleList.clear();
int infoSize = data::curUser.titleInfo.size();
for(int i = 0; i < infoSize; i++)
{
uint64_t sid = data::curUser.titleInfo[i].saveID;
SDL_Texture *iconPtr = data::getTitleIconByTID(sid);
bool fav = data::isFavorite(sid);
titleList.emplace_back(128, 128, fav, iconPtr);
}
}
void ui::ttlReset()
{
clrShft = 0;
clrAdd = true;
selRectX = 38;
selRectY = 38;
x = 34;
y = 69;
//Reset data
data::selData = 0;
}
static inline void updateTitleScroll()
{
if(selRectY > 264)
y -= 48;
else if(selRectY > 144)
y -= 24;
else if(selRectY < -82)
y += 48;
else if(selRectY < 38)
y += 24;
}
void ui::ttlUpdate()
{
ttlOpts->update();
if(ttlOptsPanel->isOpen() || infoPanel->isOpen())
return;
uint64_t down = ui::padKeysDown();
switch(down)
{
case HidNpadButton_A:
if(fs::mountSave(data::curData.saveInfo))
{
fldInit();
ui::changeState(FLD_SEL);
}
else
ui::showPopup(POP_FRAME_DEFAULT, "Failed to Mount save!");
break;
case HidNpadButton_B:
ui::usrMenuSetActive(true);
ui::changeState(USR_SEL);
break;
case HidNpadButton_X:
ttlOpts->setActive(true);
ttlOptsPanel->openPanel();
break;
case HidNpadButton_Y:
{
uint64_t sid = data::curData.saveID;
data::favoriteTitle(sid);
setupTiles(NULL);
if(data::isFavorite(sid))
data::selData = data::getTitleIndexInUser(data::curUser, sid);
}
break;
case HidNpadButton_StickLUp:
case HidNpadButton_Up:
data::selData -= 7;
if(data::selData < 0)
data::selData = 0;
break;
case HidNpadButton_StickLDown:
case HidNpadButton_Down:
data::selData += 7;
if(data::selData > (int)data::curUser.titleInfo.size() - 1)
data::selData = data::curUser.titleInfo.size() - 1;
break;
case HidNpadButton_StickLLeft:
case HidNpadButton_Left:
if(data::selData > 0)
--data::selData;
break;
case HidNpadButton_StickLRight:
case HidNpadButton_Right:
if(data::selData < (int)data::curUser.titleInfo.size() - 1)
++data::selData;
break;
case HidNpadButton_L:
if(data::selData - 21 > 0)
data::selData -= 21;
else
data::selData = 0;
break;
case HidNpadButton_R:
if(data::selData + 21 < (int)data::curUser.titleInfo.size())
data::selData += 21;
else
data::selData = data::curUser.titleInfo.size() - 1;
break;
}
}
void ui::ttlDraw(SDL_Texture *target)
{
updateTitleScroll();
if(clrAdd)
{
clrShft += 6;
if(clrShft >= 0x72)
clrAdd = false;
}
else
{
clrShft -= 3;
if(clrShft <= 0)
clrAdd = true;
}
int totalTiles = titleList.size();
int selX = 0, selY = 0;
for(int tY = y, i = 0; i < totalTiles; tY += 144)
{
int endRow = i + 7;
for(int tX = x; i < endRow; tX += 144, i++)
{
if(i >= totalTiles)
break;
if(i == data::selData && (ui::mstate == TTL_SEL|| ui::mstate == FLD_SEL))
{
//save x and y for selected for later so it's drawn on top.
//I can't find anyway to change the Z for SDL.
selX = tX;
selY = tY;
selRectX = tX - 24;
selRectY = tY - 24;
}
else
titleList[i].draw(target, tX, tY, false);
}
}
if(ui::mstate == TTL_SEL || ui::mstate == FLD_SEL)
{
//Draw selected after so it's on top
ui::drawBoundBox(target, selRectX, selRectY, 176, 176, clrShft);
titleList[data::selData].draw(target, selX, selY, true);
if(ui::mstate == TTL_SEL)
gfx::drawTextf(NULL, 18, ttlHelpX, 673, &ui::txtCont, ui::titleHelp.c_str());
}
}
//Todo make less hardcoded
void titleTile::draw(SDL_Texture *target, int x, int y, bool sel)
{
if(sel)
{
unsigned xScale = w * 1.28, yScale = w * 1.28;
if(wS < xScale)
wS += 18;
if(hS < yScale)
hS += 18;
}
else
{
if(wS > w)
wS -= 18;
if(hS > h)
hS -= 18;
}
int dX = x - ((wS - w) / 2);
int dY = y - ((hS - h) / 2);
gfx::texDrawStretch(target, icon, dX, dY, wS, hS);
if(fav)
gfx::drawTextf(target, 20, dX + 8, dY + 8, &ui::heartColor, "");
}

View File

@@ -1,170 +0,0 @@
#include <string>
#include <vector>
#include "data.h"
#include "ui.h"
#include "uiupdate.h"
#include "file.h"
#include "util.h"
//Where to start in titles
static int start = 0;
//Color shift for rect
static uint8_t clrShft = 0;
//Whether or not we're adding or subtracting from clrShft
static bool clrAdd = true;
//Selected rectangle X and Y.
static unsigned selRectX = 66, selRectY = 94;
static inline void reset()
{
start = 0;
selRectX = 66;
selRectY = 94;
data::selData = 0;
}
void ui::drawTitleMenu()
{
if(clrAdd)
{
clrShft += 6;
if(clrShft >= 0x72)
clrAdd = false;
}
else
{
clrShft -= 3;
if(clrShft <= 0)
clrAdd = true;
}
unsigned x = 70, y = 98;
unsigned endTitle = start + 32;
if(start + 32 > (int)data::curUser.titles.size())
endTitle = data::curUser.titles.size();
//draw Rect so it's always behind icons
drawBoundBox(selRectX, selRectY, 140, 140, clrShft);
for(unsigned i = start; i < endTitle; y += 136)
{
unsigned endRow = i + 8;
for(unsigned tX = x; i < endRow; i++, tX += 144)
{
if(i == endTitle)
break;
if((int)i == data::selData)
{
selRectX = tX - 6;
selRectY = y - 6;
unsigned titleWidth = gfx::getTextWidth(data::curData.getTitle().c_str(), 18);
int rectWidth = titleWidth + 32, rectX = (tX + 64) - (rectWidth / 2);
if(rectX < 16)
rectX = 16;
else if(rectX + rectWidth > 1264)
rectX = 1264 - rectWidth;
ui::drawTextbox(rectX, y - 50, rectWidth, 38);
gfx::drawTextf(18, rectX + 16, y - 40, &ui::txtDiag, data::curData.getTitle().c_str());
}
if(data::curUser.titles[i].getFav())
data::curUser.titles[i].drawIconFav(false, tX, y);
else
data::curUser.titles[i].drawIcon(false, tX, y);
}
}
}
void ui::updateTitleMenu(const uint64_t& down, const uint64_t& held)
{
switch(down)
{
case HidNpadButton_A:
if(fs::mountSave(data::curUser, data::curData))
{
folderMenuPrepare(data::curUser, data::curData);
ui::folderMenuInfo = util::getInfoString(data::curUser, data::curData);
ui::changeState(FLD_SEL);
}
break;
case HidNpadButton_B:
reset();
ui::changeState(USR_SEL);
break;
case HidNpadButton_X:
data::favoriteTitle(data::curData);
break;
case HidNpadButton_Y:
fs::dumpAllUserSaves(data::curUser);
break;
case HidNpadButton_L:
if(--data::selUser < 0)
data::selUser = data::users.size() - 1;
reset();
ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str());
break;
case HidNpadButton_R:
if(++data::selUser == (int)data::users.size())
data::selUser = 0;
reset();
ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str());
break;
case HidNpadButton_ZR:
if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseNand.c_str(), data::curData.getTitle().c_str()))
{
fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId_User, data::curData.getSaveID());
data::loadUsersTitles(false);
data::selData = 0;
}
break;
case HidNpadButton_Minus:
if(ui::confirm(false, ui::confBlacklist.c_str(), data::curUser.titles[data::selData].getTitle().c_str()))
data::blacklistAdd(data::curData);
break;
case HidNpadButton_StickLUp:
case HidNpadButton_Up:
data::selData -= 8;
if(data::selData < 0)
data::selData = 0;
break;
case HidNpadButton_StickLDown:
case HidNpadButton_Down:
data::selData += 8;
if(data::selData > (int)data::curUser.titles.size() - 1)
data::selData = data::curUser.titles.size() - 1;
break;
case HidNpadButton_StickLLeft:
case HidNpadButton_Left:
if(data::selData > 0)
--data::selData;
break;
case HidNpadButton_StickLRight:
case HidNpadButton_Right:
if(data::selData < (int)data::curUser.titles.size() - 1)
++data::selData;
break;
}
if(data::selData < start)
start -= 8;
else if(data::selData - start >= 32)
start += 8;
}

View File

@@ -1,474 +0,0 @@
#include <string>
#include <vector>
#include <cstdlib>
#include <switch.h>
#include <sys/stat.h>
#include "ui.h"
#include "data.h"
#include "file.h"
#include "util.h"
static ui::menu userMenu, titleMenu, exMenu, optMenu;
extern ui::menu folderMenu;
void ui::textUserPrep()
{
userMenu.reset();
userMenu.setParams(76, 98, 310);
for(unsigned i = 0; i < data::users.size(); i++)
userMenu.addOpt(data::users[i].getUsername());
}
void ui::textTitlePrep(data::user& u)
{
titleMenu.reset();
titleMenu.setParams(76, 98, 310);
for(unsigned i = 0; i < u.titles.size(); i++)
{
if(u.titles[i].getFav())
titleMenu.addOpt("" + u.titles[i].getTitle());
else
titleMenu.addOpt(u.titles[i].getTitle());
}
}
void ui::textUserMenuUpdate(const uint64_t& down, const uint64_t& held)
{
userMenu.handleInput(down, held);
data::selUser = userMenu.getSelected();
switch(down)
{
case HidNpadButton_A:
if(data::curUser.titles.size() > 0)
{
ui::textTitlePrep(data::curUser);
ui::changeState(TXT_TTL);
}
else
ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str());
break;
case HidNpadButton_X:
ui::textMode = false;
ui::changeState(USR_SEL);
break;
case HidNpadButton_Y:
{
bool cont = true;
for(unsigned i = 0; i < data::users.size() - 2; i++)
{
if(cont)
cont = fs::dumpAllUserSaves(data::users[i]);
}
}
break;
case HidNpadButton_R:
util::checkForUpdate();
break;
case HidNpadButton_ZR:
ui::changeState(EX_MNU);
break;
case HidNpadButton_Minus:
ui::changeState(OPT_MNU);
break;
}
}
void ui::drawTextUserMenu()
{
userMenu.draw(&ui::txtCont);
}
void ui::textTitleMenuUpdate(const uint64_t& down, const uint64_t& held)
{
titleMenu.handleInput(down, held);
data::selData = titleMenu.getSelected();
switch(down)
{
case HidNpadButton_A:
if(fs::mountSave(data::curUser, data::curData))
{
folderMenuPrepare(data::curUser, data::curData);
ui::folderMenuInfo = util::getInfoString(data::curUser, data::curData);
ui::changeState(TXT_FLD);
}
break;
case HidNpadButton_B:
ui::changeState(TXT_USR);
break;
case HidNpadButton_X:
data::favoriteTitle(data::curData);
textTitlePrep(data::curUser);
break;
case HidNpadButton_Y:
fs::dumpAllUserSaves(data::curUser);
break;
case HidNpadButton_L:
if(--data::selUser < 0)
data::selUser = data::users.size() - 1;
ui::textTitlePrep(data::curUser);
ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str());
break;
case HidNpadButton_R:
if(++data::selUser == (int)data::users.size())
data::selUser = 0;
ui::textTitlePrep(data::curUser);
ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str());
break;
case HidNpadButton_ZR:
if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseNand.c_str(), data::curData.getTitle().c_str()))
{
fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId_User, data::curData.getSaveID());
data::loadUsersTitles(false);
data::selData = 0;
}
break;
case HidNpadButton_Minus:
if(ui::confirm(false, ui::confBlacklist.c_str(), data::curUser.titles[data::selData].getTitle().c_str()))
data::blacklistAdd(data::curData);
break;
}
}
void ui::drawTextTitleMenu()
{
titleMenu.draw(&ui::txtCont);
}
void ui::textFolderMenuUpdate(const uint64_t& down, const uint64_t& held)
{
folderMenu.handleInput(down, held);
switch(down)
{
case HidNpadButton_A:
if(folderMenu.getSelected() == 0)
ui::createNewBackup(held);
else
ui::overwriteBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_B:
fs::unmountSave();
fs::freePathFilters();
ui::changeState(TXT_TTL);
break;
case HidNpadButton_X:
if(folderMenu.getSelected() > 0)
ui::deleteBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_Y:
if(folderMenu.getSelected() > 0)
ui::restoreBackup(folderMenu.getSelected() - 1);
break;
case HidNpadButton_ZR:
if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseFolder.c_str(), data::curData.getTitle().c_str()))
{
fs::delDir("sv:/");
fsdevCommitDevice("sv");
}
break;
case HidNpadButton_Minus:
advModePrep("sv:/", data::curData.getType(), true);
ui::changeState(ADV_MDE);
break;
}
}
void ui::drawTextFolderMenu()
{
titleMenu.draw(&ui::txtCont);
folderMenu.draw(&ui::txtCont);
}
void ui::exMenuPrep()
{
exMenu.reset();
exMenu.setParams(76, 98, 310);
for(unsigned i = 0; i < 11; i++)
exMenu.addOpt(ui::exMenuStr[i]);
}
void ui::updateExMenu(const uint64_t& down, const uint64_t& held)
{
exMenu.handleInput(down, held);
if(down & HidNpadButton_A)
{
fsdevUnmountDevice("sv");
FsFileSystem sv;
data::curData.setType(FsSaveDataType_System);
switch(exMenu.getSelected())
{
case 0:
data::curData.setType(FsSaveDataType_Bcat);
advModePrep("sdmc:/", data::curData.getType(), false);
ui::changeState(ADV_MDE);
break;
case 1:
fsdevUnmountDevice("sv");
fsOpenBisFileSystem(&sv, FsBisPartitionId_CalibrationFile, "");
fsdevMountDevice("prodInfo-f", sv);
advModePrep("profInfo-f:/", FsSaveDataType_System, false);
ui::changeState(ADV_MDE);
break;
case 2:
fsOpenBisFileSystem(&sv, FsBisPartitionId_SafeMode, "");
fsdevMountDevice("safe", sv);
advModePrep("safe:/", FsSaveDataType_System, false);
ui::changeState(ADV_MDE);
break;
case 3:
fsOpenBisFileSystem(&sv, FsBisPartitionId_System, "");
fsdevMountDevice("sys", sv);
advModePrep("sys:/", FsSaveDataType_System, false);
ui::changeState(ADV_MDE);
break;
case 4:
fsOpenBisFileSystem(&sv, FsBisPartitionId_User, "");
fsdevMountDevice("user", sv);
advModePrep("user:/", FsSaveDataType_System, false);
ui::changeState(ADV_MDE);
break;
case 5:
{
fsOpenBisFileSystem(&sv, FsBisPartitionId_System, "");
fsdevMountDevice("sv", sv);
std::string delPath = "sv:/Contents/placehld/";
fs::dirList plcHld(delPath);
for(unsigned i = 0; i < plcHld.getCount(); i++)
{
std::string fullPath = delPath + plcHld.getItem(i);
std::remove(fullPath.c_str());
}
fsdevUnmountDevice("sv");
if(ui::confirm(false, "Restart?"))
{
bpcInitialize();
bpcRebootSystem();
}
}
break;
case 6:
{
std::string idStr = util::getStringInput("0100000000000000", "Enter Process ID", 18, 0, NULL);
if(!idStr.empty())
{
uint64_t termID = std::strtoull(idStr.c_str(), NULL, 16);
if(R_SUCCEEDED(pmshellTerminateProgram(termID)))
ui::showMessage("Success!", "Process %s successfully shutdown.", idStr.c_str());
}
}
break;
case 7:
{
std::string idStr = util::getStringInput("8000000000000000", "Enter Sys Save ID", 18, 0, NULL);
uint64_t mountID = std::strtoull(idStr.c_str(), NULL, 16);
if(R_SUCCEEDED(fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, mountID, (AccountUid) {0})))
{
fsdevMountDevice("sv", sv);
advModePrep("sv:/", data::curData.getType(), true);
ui::changeState(ADV_MDE);
}
}
break;
case 8:
data::loadUsersTitles(true);
break;
case 9:
{
FsFileSystem tromfs;
//Result res = romfsMountFromCurrentProcess("tromfs"); << Works too, but is kinda weird
if(R_SUCCEEDED(fsOpenDataFileSystemByCurrentProcess(&tromfs)))
{
fsdevMountDevice("tromfs", tromfs);
advModePrep("tromfs:/", FsSaveDataType_Account, false);
ui::changeState(ADV_MDE);
}
}
break;
case 10:
{
fs::logClose();
remove(std::string(fs::getWorkDir() + "log.txt").c_str());
std::string zipName = "JKSV - " + util::getDateTime(util::DATE_FMT_ASC) + ".zip";
zipFile jksv = zipOpen(std::string("sdmc:/" + zipName).c_str(), 0);
fs::copyDirToZip(fs::getWorkDir(), &jksv);
zipClose(jksv, NULL);
rename(std::string("sdmc:/" + zipName).c_str(), std::string(fs::getWorkDir() + zipName).c_str());
fs::logOpen();
}
break;
}
}
else if(down & HidNpadButton_B)
{
fsdevUnmountDevice("sv");
ui::changeState(ui::textMode ? TXT_USR : USR_SEL);
prevState = USR_SEL;
}
}
void ui::drawExMenu()
{
exMenu.draw(&ui::txtCont);
}
static inline void switchBool(bool& sw)
{
sw ? sw = false : sw = true;
}
static inline std::string getBoolText(bool b)
{
return b ? ui::on : ui::off;
}
static inline void changeSort()
{
if(++data::sortType > 2)
data::sortType = 0;
}
void ui::optMenuInit()
{
optMenu.setParams(76, 98, 310);
for(unsigned i = 0; i < 15; i++)
optMenu.addOpt(ui::optMenuStr[i]);
}
void ui::updateOptMenu(const uint64_t& down, const uint64_t& held)
{
optMenu.handleInput(down, held);
//Update Menu Options to reflect changes
optMenu.editOpt(0, optMenuStr[0] + getBoolText(data::incDev));
optMenu.editOpt(1, optMenuStr[1] + getBoolText(data::autoBack));
optMenu.editOpt(2, optMenuStr[2] + getBoolText(data::ovrClk));
optMenu.editOpt(3, optMenuStr[3] + getBoolText(data::holdDel));
optMenu.editOpt(4, optMenuStr[4] + getBoolText(data::holdRest));
optMenu.editOpt(5, optMenuStr[5] + getBoolText(data::holdOver));
optMenu.editOpt(6, optMenuStr[6] + getBoolText(data::forceMount));
optMenu.editOpt(7, optMenuStr[7] + getBoolText(data::accSysSave));
optMenu.editOpt(8, optMenuStr[8] + getBoolText(data::sysSaveWrite));
optMenu.editOpt(9, optMenuStr[9] + getBoolText(ui::textMode));
optMenu.editOpt(10, optMenuStr[10] + getBoolText(data::directFsCmd));
optMenu.editOpt(11, optMenuStr[11] + getBoolText(data::skipUser));
optMenu.editOpt(12, optMenuStr[12] + getBoolText(data::zip));
optMenu.editOpt(13, optMenuStr[13] + ui::sortString[data::sortType]);
optMenu.editOpt(14, optMenuStr[14] + getBoolText(data::langOverride));
if(down & HidNpadButton_A)
{
switch(optMenu.getSelected())
{
case 0:
switchBool(data::incDev);
break;
case 1:
switchBool(data::autoBack);
break;
case 2:
switchBool(data::ovrClk);
break;
case 3:
switchBool(data::holdDel);
break;
case 4:
switchBool(data::holdRest);
break;
case 5:
switchBool(data::holdOver);
break;
case 6:
switchBool(data::forceMount);
break;
case 7:
switchBool(data::accSysSave);
break;
case 8:
switchBool(data::sysSaveWrite);
break;
case 9:
switchBool(ui::textMode);
break;
case 10:
switchBool(data::directFsCmd);
break;
case 11:
switchBool(data::skipUser);
break;
case 12:
switchBool(data::zip);
break;
case 13:
changeSort();
data::loadUsersTitles(false);
break;
case 14:
switchBool(data::langOverride);
break;
}
}
else if(down & HidNpadButton_X)
data::restoreDefaultConfig();
else if(down & HidNpadButton_B)
ui::changeState(ui::textMode ? TXT_USR : USR_SEL);
}
void ui::drawOptMenu()
{
optMenu.draw(&ui::txtCont);
gfx::drawTextfWrap(18, 466, 98, 730, &ui::txtCont, ui::optMenuExp[optMenu.getSelected()].c_str());
}

View File

@@ -1,17 +1,24 @@
#include <string>
#include <unordered_map>
#include "file.h"
#include "uistr.h"
//8
const std::string ui::loadGlyphArray[8] =
//Map to associate external string names to unsigned ints for switch case.
static std::unordered_map<std::string, unsigned> uistrdef =
{
"\ue020", "\ue021", "\ue022", "\ue023",
"\ue024", "\ue025", "\ue026", "\ue027"
{"author", 0}, {"userHelp", 1}, {"titleHelp", 2}, {"folderHelp", 3}, {"optHelp", 4},
{"yt", 5}, {"nt", 6}, {"on", 7}, {"off", 8}, {"confirmBlacklist", 9}, {"confirmOverwrite", 10},
{"confirmRestore", 11}, {"confirmDelete", 12}, {"confirmCopy", 13}, {"confirmEraseNand", 14},
{"confirmReset", 15}, {"confirmHead", 16}, {"copyHead", 17}, {"noSavesFound", 18},
{"advMenu", 19}, {"extMenu", 20}, {"optMenu", 21}, {"optMenuExp", 22}, {"holdingText", 23},
{"errorConnecting", 24}, {"noUpdate", 25}, {"sortType", 26}, {"saveCreated", 27}, {"saveCreateFailed", 28},
{"saveDataResetSuccess", 29}, {"saveDataDeleteSuccess", 30}
};
std::string ui::author = "NULL";
std::string ui::userHelp = "[A] Select [Y] Dump All [X] UI Mode [R] Update [-] Options [ZR] Extras";
std::string ui::titleHelp = "[A] Select [L][R] Change User [Y] Dump All [X] Favorite [-] BlackList [ZR] Erase [B] Back";
std::string ui::userHelp = "[A] Select [X] User Options";
std::string ui::titleHelp = "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back";
std::string ui::folderHelp = "[-] File Mode [L]/[R]+[A] Auto [A] Backup [Y] Restore [X] Delete Selected [ZR] Erase [B] Back";
std::string ui::optHelp = "[A] Toggle [X] Defaults [B] Back";
std::string ui::yt = "Yes [A]", ui::nt = "No [B]";
@@ -24,68 +31,183 @@ std::string ui::confCopy = "Are you sure you want to copy #%s# to #%s#?";
std::string ui::confirmHead = "Confirm";
std::string ui::copyHead = "Copying File...";
std::string ui::confEraseNand = "*WARNING*: This *will* erase the save data for #%s# *from your system*. This is the same as deleting it from #Data Management#! Are you sure you want to continue?";
std::string ui::confEraseFolder = "*WARNING*: This *will* delete the current save data for #%s# *from your system*! Are you sure you want to continue?";
std::string ui::noSavesFound = "No saves found for #%s#!";
std::string ui::saveCreated = "Save data created for %s!";
std::string ui::saveCreateFailed = "Save data creation failed!";
std::string ui::saveDataReset = "Are you sure want to reset your current save data for %s?";
std::string ui::saveDataResetSuccess = "Save for %s reset!";
std::string ui::saveDataDeleteSuccess = "Save data for %s deleted!";
std::string ui::errorConnecting = "Error Connecting!";
std::string ui::noUpdate = "No updates available!";
std::string ui::advMenuStr[6] =
{
"Copy to ",
"Delete",
"Rename",
"Make Dir",
"Properties",
"Close"
};
std::string ui::exMenuStr[11] =
{
"SD to SD Browser",
"BIS: PRODINFOF",
"BIS: SAFE",
"BIS: SYSTEM",
"BIS: USER",
"Remove Update",
"Terminate Process",
"Mount System Save",
"Rescan Titles",
"Mount Process RomFS",
"Backup JKSV Folder"
};
std::string ui::optMenuStr[15] =
{
"Include Dev Sv: ",
"AutoBackup: ",
"Overclock: ",
"Hold to Delete: ",
"Hold to Restore: ",
"Hold to Overwrite: ",
"Force Mount: ",
"Account Sys. Saves: ",
"Write to Sys. Saves: ",
"Text UI Mode: ",
"Direct FS Cmd: ",
"Skip User Select: ",
"Export to ZIP: ",
"Sort: ",
"Language Override: "
};
std::string ui::optMenuExp[15] =
{
"Includes Device Save data in user accounts.",
"Automatically creates a save backup before restoring a save.",
"Applies a small CPU over clock to 1224Mhz at boot. This is the same speed developer units run at.",
"Whether or not holding [A] is required when deleting folders and files.",
"Whether or not holding [A] is required when restoring save data.",
"Whether or not holding [A] is required when overwriting saves on SD.",
"When enabled, JKSV will only load and show save data that can be opened. When disabled, everything found will be shown.",
"When enabled, system save data tied to accounts will be shown.",
"Controls whether system save data and partitions can have files and data written and deleted from them. *This can be extremely dangerous if you don't know what you're doing!*",
"Changes the UI to be text menu based like the original JKSM for 3DS.",
"Directly uses the Switch's FS commands to copy files instead of stdio.",
"Skips the user selection screen and jumps directly to the first user account found.",
"Exports saves to ZIP files.",
"Changes the way titles are sorted and listed.",
"Forces English to be used regardless of system language."
};
std::string ui::advMenuStr[6] = { "Copy to ", "Delete", "Rename", "Make Dir", "Properties", "Close" };
std::string ui::exMenuStr[11] = { "SD to SD Browser", "BIS: PRODINFOF", "BIS: SAFE", "BIS: SYSTEM", "BIS: USER", "Remove Update", "Terminate Process", "Mount System Save", "Rescan Titles", "Mount Process RomFS", "Backup JKSV Folder" };
std::string ui::optMenuStr[15] = { "Include Device Saves: ", "AutoBackup: ", "Overclock: ", "Hold to Delete: ", "Hold to Restore: ", "Hold to Overwrite: ", "Force Mount: ", "Account Sys. Saves: ", "Write to Sys. Saves: ", "Text UI Mode: ", "Direct FS Cmd: ", "Skip User Select: ", "Export to ZIP: ", "Language Override: ", "Sort: "};
std::string ui::holdingText[3] = { "(Hold) ", "(Keep Holding) ", "(Almost there!) " };
std::string ui::sortString[3] = { "Alphabetical", "Time Played", "Last Played" };
std::string ui::usrOptString[1] = { "Create Save Data" };
std::string ui::titleOptString[4] = {"Information", "Blacklist", "Reset Save Data", "Delete Save Filesystem"};
void ui::loadTrans()
{
bool transFile = fs::fileExists(fs::getWorkDir() + "trans.txt");
if(!transFile && data::sysLang == SetLanguage_ENUS)
return;//Don't bother loading from file. It serves as a translation guide
std::string file;
if(transFile)
file = fs::getWorkDir() + "trans.txt";
else
{
file = "romfs:/lang/";
switch(data::sysLang)
{
case SetLanguage_ZHCN:
case SetLanguage_ZHHANS:
file += "zh-CN.txt";
break;
case SetLanguage_ZHTW:
case SetLanguage_ZHHANT:
file += "zh-TW.txt";
break;
default:
return;
break;
}
}
fs::dataFile lang(file);
while(lang.readNextLine(true))
{
switch(uistrdef[lang.getName()])
{
case 0:
ui::author = lang.getNextValueStr();
break;
case 1:
ui::userHelp = lang.getNextValueStr();
break;
case 2:
ui::titleHelp = lang.getNextValueStr();
break;
case 3:
ui::folderHelp = lang.getNextValueStr();
break;
case 4:
ui::optHelp = lang.getNextValueStr();
break;
case 5:
ui::yt = lang.getNextValueStr();
break;
case 6:
ui::nt = lang.getNextValueStr();
break;
case 7:
ui::on = lang.getNextValueStr();
break;
case 8:
ui::off = lang.getNextValueStr();
break;
case 9:
ui::confBlacklist = lang.getNextValueStr();
break;
case 10:
ui::confOverwrite = lang.getNextValueStr();
break;
case 11:
ui::confRestore = lang.getNextValueStr();
break;
case 12:
ui::confDel = lang.getNextValueStr();
break;
case 13:
ui::confCopy = lang.getNextValueStr();
break;
case 14:
ui::confEraseNand = lang.getNextValueStr();
break;
case 15:
ui::saveDataReset = lang.getNextValueStr();
break;
case 16:
ui::confirmHead = lang.getNextValueStr();
break;
case 17:
ui::copyHead = lang.getNextValueStr();
break;
case 18:
ui::noSavesFound = lang.getNextValueStr();
break;
case 19:
{
int ind = lang.getNextValueInt();
ui::advMenuStr[ind] = lang.getNextValueStr();
}
break;
case 20:
{
int ind = lang.getNextValueInt();
ui::exMenuStr[ind] = lang.getNextValueStr();
}
break;
case 21:
{
int ind = lang.getNextValueInt();
ui::optMenuStr[ind] = lang.getNextValueStr();
}
break;
case 22:
break;
case 23:
{
int ind = lang.getNextValueInt();
ui::holdingText[ind] = lang.getNextValueStr();
}
break;
case 24:
ui::errorConnecting = lang.getNextValueStr();
break;
case 25:
ui::noUpdate = lang.getNextValueStr();
break;
case 26:
{
int ind = lang.getNextValueInt();
ui::sortString[ind] = lang.getNextValueStr();
}
break;
default:
ui::showMessage("*Translation File Error:*", "On Line: %s\n*%s* is not a known or valid string name.", lang.getLine(), lang.getName());
break;
}
}
}

237
src/ui/usr.cpp Normal file
View File

@@ -0,0 +1,237 @@
#include <string>
#include <vector>
#include <switch.h>
#include "file.h"
#include "data.h"
#include "ui.h"
#include "util.h"
#include "type.h"
#include "usr.h"
#include "ttl.h"
//Main menu/Users + options, folder
static ui::menu *usrMenu, *usrOptMenu, *saveCreateMenu;
static ui::slideOutPanel *usrOptPanel, *saveCreatePanel;
//This stores save ids to match with saveCreateMenu
//Probably needs/should be changed
static std::vector<uint64_t> sids;
static unsigned optsPos = 0, extPos = 0, usrHelpX = 0;
fs::backupArgs backargs;
static void onMainChange(void *a)
{
if(usrMenu->getSelected() < (int)data::users.size())
{
data::selUser = usrMenu->getSelected();
ui::ttlReset();
ui::setupTiles(NULL);
}
}
static void toOPT(void *a)
{
ui::changeState(OPT_MNU);
ui::usrMenuSetActive(false);
}
static void toEXT(void *a)
{
ui::changeState(EX_MNU);
ui::usrMenuSetActive(false);
}
static void toMAIN(void *a)
{
if(ui::padKeysDown() & HidNpadButton_B)
{
ui::changeState(USR_SEL);
ui::usrMenuSetActive(true);
}
}
static void usrOptCallback(void *a)
{
switch(ui::padKeysDown())
{
case HidNpadButton_B:
usrOptPanel->closePanel();
usrMenu->setActive(true);
usrOptMenu->setActive(false);
break;
}
}
static void saveCreateCallback(void *a)
{
switch(ui::padKeysDown())
{
case HidNpadButton_B:
usrOptMenu->setActive(true);
saveCreateMenu->setActive(false);
saveCreatePanel->closePanel();
usrOptPanel->openPanel();
break;
}
}
static void usrOptSaveCreate(void *a)
{
ui::updateInput();
usrOptMenu->setActive(false);
saveCreateMenu->setActive(true);
usrOptPanel->closePanel();
saveCreatePanel->openPanel();
}
static void usrOptPanelDraw(void *a)
{
SDL_Texture *panel = (SDL_Texture *)a;
usrOptMenu->draw(panel, &ui::txtCont, true);
}
static void saveCreatePanelDraw(void *a)
{
SDL_Texture *panel = (SDL_Texture *)a;
saveCreateMenu->draw(panel, &ui::txtCont, true);
}
static void createSaveData(void *a)
{
ui::menu *in = (ui::menu *)a;
uint64_t sid = sids[in->getSelected()];
data::titleInfo *create = data::getTitleInfoByTID(sid);
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(FsSaveDataAttribute));
attr.application_id = sid;
attr.uid = data::curUser.getUID();
attr.system_save_data_id = 0;
attr.save_data_type = FsSaveDataType_Account;
attr.save_data_rank = 0;
attr.save_data_index = 0;
FsSaveDataCreationInfo svCreate;
memset(&svCreate, 0, sizeof(FsSaveDataCreationInfo));
svCreate.save_data_size = create->nacp.user_account_save_data_size;
svCreate.journal_size = create->nacp.user_account_save_data_journal_size;
svCreate.available_size = create->nacp.user_account_save_data_size;
svCreate.owner_id = create->nacp.save_data_owner_id;
svCreate.flags = 0;
svCreate.save_data_space_id = FsSaveDataSpaceId_User;
FsSaveDataMetaInfo meta;
memset(&meta, 0, sizeof(FsSaveDataMetaInfo));
meta.size = 0x40060;
meta.type = FsSaveDataMetaType_Thumbnail;
Result res = 0;
if(R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &svCreate, &meta)))
{
ui::showPopup(POP_FRAME_DEFAULT, ui::saveCreated.c_str(), create->title.c_str());
data::loadUsersTitles(false);
ui::setupTiles(NULL);
}
else
{
ui::showPopup(POP_FRAME_DEFAULT, ui::saveCreateFailed.c_str());
}
}
void ui::usrInit()
{
usrMenu = new ui::menu;
usrOptMenu = new ui::menu;
saveCreateMenu = new ui::menu;
usrMenu->setParams(64, 16, 0, 96, 4);
usrOptMenu->setParams(8, 32, 390, 18, 8);
usrOptMenu->setCallback(usrOptCallback, NULL);
saveCreateMenu->setParams(8, 32, 390, 18, 8);
saveCreateMenu->setCallback(saveCreateCallback, NULL);
for(data::user u : data::users)
{
usrMenu->addOpt(u.getUserIcon(), u.getUsername());
unsigned ind = usrMenu->getOptPos(u.getUsername());
usrMenu->setOptFunc(ind, FUNC_A, toTTL, NULL);
}
usrMenu->addOpt(NULL, "Settings");
optsPos = usrMenu->getOptPos("Settings");
usrMenu->setOptFunc(optsPos, FUNC_A, toOPT, NULL);
usrMenu->addOpt(NULL, "Extras");
extPos = usrMenu->getOptPos("Extras");
usrMenu->setOptFunc(extPos, FUNC_A, toEXT, NULL);
usrMenu->setOnChangeFunc(onMainChange);
usrMenu->editParam(MENU_RECT_WIDTH, 126);
usrOptPanel = new ui::slideOutPanel(410, 720, 0, usrOptPanelDraw);
ui::addPanel(usrOptPanel);
usrOptMenu->addOpt(NULL, ui::usrOptString[0]);
usrOptMenu->setOptFunc(0, FUNC_A, usrOptSaveCreate, NULL);
usrOptMenu->setActive(false);
saveCreatePanel = new ui::slideOutPanel(410, 720, 0, saveCreatePanelDraw);
saveCreateMenu->setActive(false);
ui::addPanel(saveCreatePanel);
unsigned i = 0;
for(auto& t : data::titles)
{
saveCreateMenu->addOpt(NULL, t.second.title);
saveCreateMenu->setOptFunc(i++, FUNC_A, createSaveData, saveCreateMenu);
sids.push_back(t.first);
}
setupTiles(NULL);
usrHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18);
}
void ui::usrExit()
{
delete usrOptPanel;
delete saveCreatePanel;
delete usrMenu;
delete usrOptMenu;
delete saveCreateMenu;
}
void ui::usrMenuSetActive(bool _set)
{
usrMenu->setActive(_set);
}
void ui::usrUpdate()
{
usrMenu->update();
usrOptMenu->update();
saveCreateMenu->update();
if(!usrOptMenu->getActive() && !saveCreateMenu->getActive())
{
switch(ui::padKeysDown())
{
case HidNpadButton_X:
usrOptMenu->setActive(true);
usrMenu->setActive(false);
usrOptPanel->openPanel();
break;
}
}
}
void ui::usrDraw(SDL_Texture *target)
{
usrMenu->draw(target, &ui::txtCont, false);
if(ui::mstate == USR_SEL)
gfx::drawTextf(NULL, 18, usrHelpX, 673, &ui::txtCont, ui::userHelp.c_str());
}

View File

@@ -1,128 +0,0 @@
#include <string>
#include <vector>
#include <switch.h>
#include "data.h"
#include "ui.h"
#include "uiupdate.h"
#include "file.h"
#include "util.h"
void ui::drawUserMenu()
{
//Static so they don't get reset every loop
static int start = 0;
static uint8_t clrShft = 0;
static bool clrAdd = true;
static unsigned selRectX = 276, selRectY = 160;
if(clrAdd)
{
clrShft += 6;
if(clrShft >= 0x72)
clrAdd = false;
}
else
{
clrShft -= 3;
if(clrShft <= 0)
clrAdd = true;
}
unsigned x = 280, y = 164;
unsigned endUser = data::users.size();
drawBoundBox(selRectX, selRectY, 140, 140, clrShft);
for(unsigned i = start; i < endUser; y += 136)
{
unsigned endRow = i + 5;
for(unsigned tX = x; i < endRow; i++, tX += 144)
{
if(i == endUser)
break;
if((int)i == data::selUser)
{
selRectX = tX - 6;
selRectY = y - 6;
unsigned userWidth = gfx::getTextWidth(data::curUser.getUsername().c_str(), 18);
int userRectWidth = userWidth + 32, userRectX = (tX + 64) - (userRectWidth / 2);
if(userRectX < 16)
userRectX = 16;
else if(userRectX + userRectWidth > 1264)
userRectX = 1264 - userRectWidth;
drawTextbox(userRectX, y - 50, userRectWidth, 38);
gfx::drawTextf(18, userRectX + 16, y - 40, &ui::txtDiag, data::curUser.getUsername().c_str());
}
data::users[i].drawIconHalf(tX, y);
}
}
}
void ui::updateUserMenu(const uint64_t& down, const uint64_t& held)
{
switch(down)
{
case HidNpadButton_A:
if(data::curUser.titles.size() > 0)
ui::changeState(TTL_SEL);
else
ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str());
break;
case HidNpadButton_X:
ui::textMode = true;
ui::changeState(TXT_USR);
break;
case HidNpadButton_Y:
{
bool cont = true;
for(unsigned i = 0; i < data::users.size() - 2; i++)
{
if(cont)
cont = fs::dumpAllUserSaves(data::users[i]);
}
}
break;
case HidNpadButton_R:
util::checkForUpdate();
break;
case HidNpadButton_ZR:
ui::changeState(EX_MNU);
break;
case HidNpadButton_Minus:
ui::changeState(OPT_MNU);
break;
case HidNpadButton_StickLUp:
case HidNpadButton_Up:
data::selUser - 5 < 0 ? data::selUser = 0 : data::selUser -= 5;
break;
case HidNpadButton_StickLDown:
case HidNpadButton_Down:
data::selUser + 5 > (int)data::users.size() - 1 ? data::selUser = data::users.size() - 1 : data::selUser += 5;
break;
case HidNpadButton_StickLLeft:
case HidNpadButton_Left:
if(data::selUser > 0)
--data::selUser;
break;
case HidNpadButton_StickLRight:
case HidNpadButton_Right:
if(data::selUser < (int)data::users.size() - 1)
++data::selUser;
break;
}
}

View File

@@ -4,10 +4,10 @@
#include <sys/stat.h>
#include <json-c/json.h>
#include "file.h"
#include "data.h"
#include "gfx.h"
#include "util.h"
#include "file.h"
#include "ui.h"
#include "curlfuncs.h"
@@ -133,17 +133,15 @@ std::string util::getDateTime(int fmt)
void util::copyDirListToMenu(const fs::dirList& d, ui::menu& m)
{
m.reset();
m.addOpt(".");
m.addOpt("..");
m.addOpt(NULL, ".");
m.addOpt(NULL, "..");
for(unsigned i = 0; i < d.getCount(); i++)
{
if(d.isDir(i))
m.addOpt("D " + d.getItem(i));
m.addOpt(NULL, "D " + d.getItem(i));
else
m.addOpt("F " + d.getItem(i));
m.addOpt(NULL, "F " + d.getItem(i));
}
m.adjust();
}
void util::removeLastFolderFromString(std::string& _path)
@@ -173,7 +171,7 @@ std::string util::safeString(const std::string& s)
}
//Check for spaces at end
while(ret[ret.length() - 1] == ' ' || ret[ret.length() - 1] == '.')
while(ret[ret.length() - 1] == ' ')
ret.erase(ret.length() - 1, 1);
return ret;
@@ -186,21 +184,25 @@ static inline std::string getTimeString(const uint32_t& _h, const uint32_t& _m)
return std::string(tmp);
}
std::string util::getInfoString(const data::user& u, const data::titledata& d)
std::string util::getInfoString(data::user& u, const uint64_t& tid)
{
std::string ret = d.getTitle() + "\n";
data::titleInfo *tinfo = data::getTitleInfoByTID(tid);
data::userTitleInfo *userTinfo = &u.titleInfo[data::selData];
ret += "TID: " + d.getTIDStr() + "\n";
ret += "SID: " + d.getSaveIDStr() + "\n";
std::string ret = tinfo->title + "\n";
ret += "TID: " + util::getIDStr(tid) + "\n";
ret += "SID: " + util::getIDStr(userTinfo->saveInfo.save_data_id) + "\n";
uint32_t hours, mins;
hours = d.getPlayTime() / 60;
mins = d.getPlayTime() - (hours * 60);
hours = userTinfo->playStats.playtimeMinutes / 60;
mins = userTinfo->playStats.playtimeMinutes - (hours * 60);
ret += "Play Time: " + getTimeString(hours, mins) + "\n";
ret += "Total Launches: " + std::to_string(d.getLaunchCount()) + "\n";
ret += "Total Launches: " + std::to_string(userTinfo->playStats.totalLaunches) + "\n";
switch(d.getType())
switch(userTinfo->saveInfo.save_data_type)
{
case FsSaveDataType_System:
ret += "System Save\n";
@@ -267,13 +269,14 @@ std::string util::getStringInput(const std::string& def, const std::string& head
return std::string(out);
}
std::string util::generateAbbrev(const data::titledata& dat)
std::string util::generateAbbrev(const uint64_t& tid)
{
size_t titleLength = dat.getTitle().length();
data::titleInfo *tmp = data::getTitleInfoByTID(tid);
size_t titleLength = tmp->safeTitle.length();
char temp[titleLength + 1];
memset(temp, 0, titleLength + 1);
memcpy(temp, dat.getTitle().c_str(), titleLength);
memcpy(temp, tmp->safeTitle.c_str(), titleLength);
std::string ret;
char *tok = strtok(temp, " ");
@@ -322,7 +325,7 @@ SDL_Texture *util::createIconGeneric(const char *txt, int fontSize)
SDL_RenderClear(gfx::render);
unsigned int x = 128 - (gfx::getTextWidth(txt, fontSize) / 2);
unsigned int y = 128 - (fontSize / 2);
gfx::drawTextf(fontSize, x, y, &ui::txtCont, txt);
gfx::drawTextf(ret, fontSize, x, y, &ui::txtCont, txt);
SDL_SetRenderTarget(gfx::render, NULL);
return ret;
}
@@ -375,3 +378,14 @@ void util::checkForUpdate()
json_object_put(jobj);
}
Result util::accountDeleteUser(AccountUid *uid)
{
Service *account = accountGetServiceSession();
struct
{
AccountUid uid;
} in = {*uid};
return serviceDispatchIn(account, 203, in);
}