mirror of
https://github.com/joel16/VITA-Homebrew-Sorter.git
synced 2025-02-27 13:57:01 +00:00
loadouts: Add a feature to backup/restore custom loadouts
This commit is contained in:
parent
e781361a6c
commit
a8bb47d116
@ -44,6 +44,8 @@ add_executable(${PROJECT_NAME}
|
||||
source/applist.cpp
|
||||
source/fs.cpp
|
||||
source/gui.cpp
|
||||
source/keyboard.cpp
|
||||
source/loadouts.cpp
|
||||
source/log.cpp
|
||||
source/main.cpp
|
||||
source/textures.cpp
|
||||
@ -84,6 +86,7 @@ vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} ${PROJECT_NAME}.self
|
||||
FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png
|
||||
FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml
|
||||
FILE res/app.png res/app.png
|
||||
FILE res/db.png res/db.png
|
||||
FILE res/folder.png res/folder.png
|
||||
FILE res/splashscreen.png res/splashscreen.png
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef _VITA_HB_SORTER_APP_LIST
|
||||
#define _VITA_HB_SORTER_APP_LIST
|
||||
#ifndef _VITA_HB_SORTER_APP_LIST_H_
|
||||
#define _VITA_HB_SORTER_APP_LIST_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
@ -1,8 +1,10 @@
|
||||
#ifndef _VITA_HB_SORTER_FS_H_
|
||||
#define _VITA_HB_SORTER_FS_H_
|
||||
|
||||
#include <psp2/io/dirent.h>
|
||||
#include <psp2/types.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FS {
|
||||
bool FileExists(const std::string &path);
|
||||
@ -11,6 +13,7 @@ namespace FS {
|
||||
int ReadFile(const std::string &path, unsigned char **buffer, SceOff *size);
|
||||
int WriteFile(const std::string &path, const void *data, SceSize size);
|
||||
int RemoveFile(const std::string &path);
|
||||
int GetDirList(const std::string &path, std::vector<SceIoDirent> &entries);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
10
include/keyboard.h
Normal file
10
include/keyboard.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _VITA_HB_SORTER_KEYBOARD_H_
|
||||
#define _VITA_HB_SORTER_KEYBOARD_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Keyboard {
|
||||
std::string GetText(const std::string &title, const std::string &initial_text);
|
||||
}
|
||||
|
||||
#endif
|
9
include/loadouts.h
Normal file
9
include/loadouts.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _VITA_HB_SORTER_LOADOUTS_H_
|
||||
#define _VITA_HB_SORTER_LOADOUTS_H_
|
||||
|
||||
namespace Loadouts {
|
||||
int Backup(void);
|
||||
int Restore(const char *name);
|
||||
}
|
||||
|
||||
#endif
|
@ -2,6 +2,7 @@
|
||||
#define _VITA_HB_SORTER_UTILS_H_
|
||||
|
||||
#include <psp2/ctrl.h>
|
||||
#include <psp2/system_param.h>
|
||||
|
||||
/// Checks whether a result code indicates success.
|
||||
#define R_SUCCEEDED(res) ((res)>=0)
|
||||
@ -16,6 +17,8 @@ namespace Utils {
|
||||
int EndAppUtil(void);
|
||||
int GetEnterButton(void);
|
||||
int GetCancelButton(void);
|
||||
int GetDateFormat(void);
|
||||
void GetDateString(char string[24], SceSystemParamDateFormat format, SceDateTime *time);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
BIN
res/db.png
Normal file
BIN
res/db.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 9.5 KiB |
Binary file not shown.
Before ![]() (image error) Size: 13 KiB After ![]() (image error) Size: 12 KiB ![]() ![]() |
Binary file not shown.
Before ![]() (image error) Size: 169 KiB After ![]() (image error) Size: 121 KiB ![]() ![]() |
Binary file not shown.
Before ![]() (image error) Size: 29 KiB After ![]() (image error) Size: 26 KiB ![]() ![]() |
@ -1,7 +1,10 @@
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <psp2/io/dirent.h>
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <psp2/io/stat.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
@ -96,7 +99,7 @@ namespace FS {
|
||||
|
||||
int RemoveFile(const std::string &path) {
|
||||
int ret = 0;
|
||||
|
||||
|
||||
if (R_FAILED(ret = sceIoRemove(path.c_str()))) {
|
||||
Log::Error("sceIoRemove(%s) failed: 0x%lx\n", path.c_str(), ret);
|
||||
return ret;
|
||||
@ -104,4 +107,72 @@ namespace FS {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string GetFileExt(const std::string &filename) {
|
||||
std::string ext = std::filesystem::path(filename).extension();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper);
|
||||
return ext;
|
||||
}
|
||||
|
||||
static bool IsDBFile(const std::string &filename) {
|
||||
std::string ext = FS::GetFileExt(filename);
|
||||
|
||||
if (!ext.compare(".DB"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Sort(const SceIoDirent &entryA, const SceIoDirent &entryB) {
|
||||
if ((SCE_S_ISDIR(entryA.d_stat.st_mode)) && !(SCE_S_ISDIR(entryB.d_stat.st_mode)))
|
||||
return true;
|
||||
else if (!(SCE_S_ISDIR(entryA.d_stat.st_mode)) && (SCE_S_ISDIR(entryB.d_stat.st_mode)))
|
||||
return false;
|
||||
else {
|
||||
std::u16string entryA_name = reinterpret_cast<const char16_t *>(entryA.d_name);
|
||||
std::u16string entryB_name = reinterpret_cast<const char16_t *>(entryB.d_name);
|
||||
std::transform(entryA_name.begin(), entryA_name.end(), entryA_name.begin(), [](unsigned char c){ return std::tolower(c); });
|
||||
std::transform(entryB_name.begin(), entryB_name.end(), entryB_name.begin(), [](unsigned char c){ return std::tolower(c); });
|
||||
|
||||
if (entryA_name.compare(entryB_name) < 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetDirList(const std::string &path, std::vector<SceIoDirent> &entries) {
|
||||
int ret = 0, i = 0;
|
||||
SceUID dir = 0;
|
||||
entries.clear();
|
||||
|
||||
if (R_FAILED(dir = sceIoDopen(path.c_str()))) {
|
||||
Log::Error("sceIoDopen(%s) failed: 0x%lx\n", path.c_str(), ret);
|
||||
return dir;
|
||||
}
|
||||
|
||||
do {
|
||||
SceIoDirent dirent;
|
||||
if (R_FAILED(ret = sceIoDread(dir, &dirent)))
|
||||
Log::Error("sceIoDread(%s) failed: 0x%lx\n", path.c_str(), ret);
|
||||
|
||||
if (!FS::IsDBFile(dirent.d_name))
|
||||
continue;
|
||||
|
||||
if (SCE_S_ISDIR(dirent.d_stat.st_mode))
|
||||
continue;
|
||||
|
||||
entries.push_back(dirent);
|
||||
i++;
|
||||
} while (ret > 0);
|
||||
|
||||
std::sort(entries.begin(), entries.end(), FS::Sort);
|
||||
|
||||
if (R_FAILED(ret = sceIoDclose(dir))) {
|
||||
Log::Error("sceIoDclose(%s) failed: 0x%lx\n", path.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
226
source/gui.cpp
226
source/gui.cpp
@ -7,7 +7,9 @@
|
||||
#include "fs.h"
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include "imgui_internal.h"
|
||||
#include "loadouts.h"
|
||||
#include "textures.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace Renderer {
|
||||
static void Start(void) {
|
||||
@ -29,6 +31,7 @@ namespace GUI {
|
||||
StateNone,
|
||||
StateConfirm,
|
||||
StateRestore,
|
||||
StateLoadoutRestore,
|
||||
StateDone
|
||||
};
|
||||
|
||||
@ -97,13 +100,29 @@ namespace GUI {
|
||||
}
|
||||
}
|
||||
|
||||
static void ConfirmRestorePopup(State *state, std::vector<AppInfoIcon> &entries) {
|
||||
static void ConfirmRestorePopup(State *state, std::vector<AppInfoIcon> &entries, const char *name) {
|
||||
ImGui::OpenPopup(*state == StateConfirm? "Confirmation" : "Restoration");
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20));
|
||||
ImGui::SetNextWindowPos(ImVec2(480.0f, 272.0f), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
if (ImGui::BeginPopupModal(*state == StateConfirm? "Confirmation" : "Restoration", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text(*state == StateConfirm? "Are you sure you want to apply this sorting method?" : "Are you sure you want to restore this backup?");
|
||||
switch (*state) {
|
||||
case StateConfirm:
|
||||
ImGui::Text("Are you sure you want to apply this sorting method?");
|
||||
break;
|
||||
|
||||
case StateRestore:
|
||||
ImGui::Text("Are you sure you want to restore this backup?");
|
||||
break;
|
||||
|
||||
case StateLoadoutRestore:
|
||||
ImGui::Text("Are you sure you want to apply this loadout?");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f));
|
||||
ImGui::Text("You must reboot your device for the changes to take effect.");
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f));
|
||||
@ -119,6 +138,8 @@ namespace GUI {
|
||||
}
|
||||
else if (*state == StateRestore)
|
||||
AppList::Restore();
|
||||
else if (*state == StateLoadoutRestore)
|
||||
Loadouts::Restore(name);
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
*state = StateDone;
|
||||
@ -165,10 +186,14 @@ namespace GUI {
|
||||
int RenderLoop(void) {
|
||||
bool done = false;
|
||||
backupExists = FS::FileExists("ux0:/data/VITAHomebrewSorter/backup/app.db");
|
||||
std::vector<AppInfoIcon> entries;
|
||||
std::vector<AppInfoIcon> apps;
|
||||
std::vector<AppInfoPage> pages;
|
||||
std::vector<AppInfoFolder> folders;
|
||||
int ret = AppList::Get(entries, pages, folders);
|
||||
std::vector<SceIoDirent> loadouts;
|
||||
int ret = AppList::Get(apps, pages, folders);
|
||||
ret = FS::GetDirList("ux0:data/VITAHomebrewSorter/loadouts", loadouts);
|
||||
int date_format = Utils::GetDateFormat();
|
||||
std::string loadout_name;
|
||||
|
||||
enum SortMode {
|
||||
SortDefault,
|
||||
@ -178,7 +203,8 @@ namespace GUI {
|
||||
|
||||
enum IconType {
|
||||
App,
|
||||
Folder,
|
||||
DB,
|
||||
Folder
|
||||
};
|
||||
|
||||
static SortMode sort = SortDefault;
|
||||
@ -192,76 +218,130 @@ namespace GUI {
|
||||
GUI::SetupWindow();
|
||||
|
||||
if (ImGui::Begin("VITA Homebrew Sorter", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
if (ImGui::RadioButton("Default", sort == SortDefault)) {
|
||||
sort = SortDefault;
|
||||
ret = AppList::Get(entries, pages, folders);
|
||||
}
|
||||
if (ImGui::BeginTabBar("VITA Homebrew Sorter tabs", ImGuiTabBarFlags_None)) {
|
||||
if (ImGui::BeginTabItem("Sort/Backup")) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::RadioButton("Asc", sort == SortAsc)) {
|
||||
sort = SortAsc;
|
||||
ret = AppList::Get(entries, pages, folders);
|
||||
std::sort(entries.begin(), entries.end(), AppList::SortAlphabeticalAsc);
|
||||
AppList::Sort(entries, pages, folders);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::RadioButton("Desc", sort == SortDesc)) {
|
||||
sort = SortDesc;
|
||||
ret = AppList::Get(entries, pages, folders);
|
||||
std::sort(entries.begin(), entries.end(), AppList::SortAlphabeticalDesc);
|
||||
AppList::Sort(entries, pages, folders);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DisableButtonInit(sort == SortDefault);
|
||||
if (ImGui::Button("Apply Sort"))
|
||||
state = StateConfirm;
|
||||
DisableButtonExit(sort == SortDefault);
|
||||
|
||||
if (backupExists) {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Restore Backup"))
|
||||
state = StateRestore;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::BeginTable("AppEntries", 5, tableFlags)) {
|
||||
ImGui::TableSetupColumn("");
|
||||
ImGui::TableSetupColumn("Title");
|
||||
ImGui::TableSetupColumn("Page ID");
|
||||
ImGui::TableSetupColumn("Page Number");
|
||||
ImGui::TableSetupColumn("Position");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(entries[i].folder? icons[Folder].id : icons[App].id), ImVec2(20, 20));
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::RadioButton("Default", sort == SortDefault)) {
|
||||
sort = SortDefault;
|
||||
ret = AppList::Get(apps, pages, folders);
|
||||
}
|
||||
|
||||
ImGui::Selectable(entries[i].title.c_str(), false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", entries[i].pageId);
|
||||
if (ImGui::RadioButton("Asc", sort == SortAsc)) {
|
||||
sort = SortAsc;
|
||||
ret = AppList::Get(apps, pages, folders);
|
||||
std::sort(apps.begin(), apps.end(), AppList::SortAlphabeticalAsc);
|
||||
AppList::Sort(apps, pages, folders);
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (entries[i].pageNo < 0)
|
||||
ImGui::Text("Inside folder");
|
||||
else
|
||||
ImGui::Text("%d", entries[i].pageNo);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", entries[i].pos);
|
||||
if (ImGui::RadioButton("Desc", sort == SortDesc)) {
|
||||
sort = SortDesc;
|
||||
ret = AppList::Get(apps, pages, folders);
|
||||
std::sort(apps.begin(), apps.end(), AppList::SortAlphabeticalDesc);
|
||||
AppList::Sort(apps, pages, folders);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DisableButtonInit(sort == SortDefault);
|
||||
if (ImGui::Button("Apply Sort"))
|
||||
state = StateConfirm;
|
||||
DisableButtonExit(sort == SortDefault);
|
||||
|
||||
if (backupExists) {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Restore Backup"))
|
||||
state = StateRestore;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::BeginTable("AppList", 5, tableFlags)) {
|
||||
ImGui::TableSetupColumn("");
|
||||
ImGui::TableSetupColumn("Title");
|
||||
ImGui::TableSetupColumn("Page ID");
|
||||
ImGui::TableSetupColumn("Page Number");
|
||||
ImGui::TableSetupColumn("Position");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(apps[i].folder? icons[Folder].id : icons[App].id), ImVec2(20, 20));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Selectable(apps[i].title.c_str(), false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", apps[i].pageId);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (apps[i].pageNo < 0)
|
||||
ImGui::Text("Inside folder");
|
||||
else
|
||||
ImGui::Text("%d", apps[i].pageNo);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", apps[i].pos);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
if (ImGui::BeginTabItem("Loadouts")) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button("Backup current loadout")) {
|
||||
if (R_SUCCEEDED(Loadouts::Backup()))
|
||||
FS::GetDirList("ux0:data/VITAHomebrewSorter/loadouts", loadouts);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::BeginTable("LoadoutList", 3, tableFlags)) {
|
||||
ImGui::TableSetupColumn("");
|
||||
ImGui::TableSetupColumn("Title");
|
||||
ImGui::TableSetupColumn("Date");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
if (loadouts.empty()) {
|
||||
ImGui::Text("No loadouts found");
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < loadouts.size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(icons[DB].id), ImVec2(20, 20));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(loadouts[i].d_name, false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
loadout_name = loadouts[i].d_name;
|
||||
state = StateLoadoutRestore;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
char date[16];
|
||||
Utils::GetDateString(date, static_cast<SceSystemParamDateFormat>(date_format), &loadouts[i].d_stat.st_mtime);
|
||||
ImGui::Text(date);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,11 +352,15 @@ namespace GUI {
|
||||
break;
|
||||
|
||||
case StateConfirm:
|
||||
GUI::ConfirmRestorePopup(&state, entries);
|
||||
GUI::ConfirmRestorePopup(&state, apps, loadout_name.c_str());
|
||||
break;
|
||||
|
||||
case StateRestore:
|
||||
GUI::ConfirmRestorePopup(&state, entries);
|
||||
GUI::ConfirmRestorePopup(&state, apps, loadout_name.c_str());
|
||||
break;
|
||||
|
||||
case StateLoadoutRestore:
|
||||
GUI::ConfirmRestorePopup(&state, apps, loadout_name.c_str());
|
||||
break;
|
||||
|
||||
case StateDone:
|
||||
|
99
source/keyboard.cpp
Normal file
99
source/keyboard.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include <codecvt>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
#include <psp2/ime_dialog.h>
|
||||
#include <vitaGL.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
/*
|
||||
Based off of libkdbvita by usineur -> https://github.com/usineur/libkbdvita/blob/master/kbdvita.c
|
||||
*/
|
||||
|
||||
namespace Keyboard {
|
||||
static bool running = false;
|
||||
static const int SCE_COMMON_DIALOG_STATUS_CANCELLED = 3;
|
||||
static uint16_t buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
|
||||
std::string text = std::string();
|
||||
|
||||
int Init(const std::string &title, const std::string &initial_text) {
|
||||
if (running)
|
||||
return -1;
|
||||
|
||||
// Clear our text buffer
|
||||
text.clear();
|
||||
|
||||
// UTF8 -> UTF16
|
||||
std::u16string title_u16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(title.data());
|
||||
std::u16string initial_text_u16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(initial_text.data());
|
||||
|
||||
SceImeDialogParam param;
|
||||
sceImeDialogParamInit(¶m);
|
||||
|
||||
param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH;
|
||||
param.languagesForced = SCE_TRUE;
|
||||
param.type = SCE_IME_TYPE_DEFAULT;
|
||||
param.option = 0;
|
||||
|
||||
param.title = (const SceWChar16 *)title_u16.c_str();
|
||||
param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;
|
||||
param.initialText = (SceWChar16 *)initial_text_u16.c_str();
|
||||
param.inputTextBuffer = buffer;
|
||||
|
||||
int ret = 0;
|
||||
if (R_FAILED(ret = sceImeDialogInit(¶m))) {
|
||||
Log::Error("sceImeDialogInit failed: 0x%lx\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
running = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SceCommonDialogStatus Update(void) {
|
||||
if (!running)
|
||||
return SCE_COMMON_DIALOG_STATUS_NONE;
|
||||
|
||||
SceCommonDialogStatus status = sceImeDialogGetStatus();
|
||||
if (status == SCE_COMMON_DIALOG_STATUS_FINISHED) {
|
||||
SceImeDialogResult result;
|
||||
std::memset(&result, 0, sizeof(SceImeDialogResult));
|
||||
sceImeDialogGetResult(&result);
|
||||
|
||||
if ((result.button == SCE_IME_DIALOG_BUTTON_CLOSE) || (result.button == SCE_IME_DIALOG_BUTTON_ENTER)) {
|
||||
std::u16string buffer_u16 = (char16_t *)buffer;
|
||||
text = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(buffer_u16.data());
|
||||
}
|
||||
else
|
||||
status = (SceCommonDialogStatus)SCE_COMMON_DIALOG_STATUS_CANCELLED;
|
||||
|
||||
sceImeDialogTerm();
|
||||
running = false;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string GetText(const std::string &title, const std::string &initial_text) {
|
||||
if (R_FAILED(Init(title, initial_text)))
|
||||
return std::string();
|
||||
|
||||
bool done = false;
|
||||
do {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
||||
SceCommonDialogStatus status = Update();
|
||||
if (status == SCE_COMMON_DIALOG_STATUS_FINISHED)
|
||||
done = true;
|
||||
else if (status != SCE_COMMON_DIALOG_STATUS_CANCELLED)
|
||||
done = false;
|
||||
|
||||
vglSwapBuffers(GL_TRUE);
|
||||
} while(!done);
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
51
source/loadouts.cpp
Normal file
51
source/loadouts.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "fs.h"
|
||||
#include "keyboard.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace Loadouts {
|
||||
constexpr char path[] = "ur0:/shell/db/app.db";
|
||||
|
||||
int Backup(void) {
|
||||
std::string filename = Keyboard::GetText("Enter loadout name", "");
|
||||
if (filename.empty())
|
||||
return -1;
|
||||
|
||||
std::string loadout_path = "ux0:data/VITAHomebrewSorter/loadouts/" + filename + ".db";
|
||||
unsigned char *data = nullptr;
|
||||
SceOff size = 0;
|
||||
|
||||
int ret = 0;
|
||||
if (R_FAILED(ret = FS::ReadFile(path, &data, &size)))
|
||||
return ret;
|
||||
|
||||
if (FS::FileExists(loadout_path)) {
|
||||
if (R_FAILED(ret = FS::RemoveFile(loadout_path)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = FS::WriteFile(loadout_path, data, size)))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Restore(const char *name) {
|
||||
std::string loadout_path = "ux0:data/VITAHomebrewSorter/loadouts/" + std::string(name);
|
||||
unsigned char *data = nullptr;
|
||||
SceOff size = 0;
|
||||
|
||||
int ret = 0;
|
||||
if (R_FAILED(ret = FS::ReadFile(loadout_path, &data, &size)))
|
||||
return ret;
|
||||
|
||||
if (FS::FileExists(path)) {
|
||||
if (R_FAILED(ret = FS::RemoveFile(path)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = FS::WriteFile(path, data, size)))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ namespace Log {
|
||||
sceIoMkdir("ux0:data/VITAHomebrewSorter", 0777);
|
||||
if (!FS::DirExists("ux0:data/VITAHomebrewSorter/backup"))
|
||||
sceIoMkdir("ux0:data/VITAHomebrewSorter/backup", 0777);
|
||||
if (!FS::DirExists("ux0:data/VITAHomebrewSorter/loadouts"))
|
||||
sceIoMkdir("ux0:data/VITAHomebrewSorter/loadouts", 0777);
|
||||
|
||||
if (!FS::FileExists("ux0:data/VITAHomebrewSorter/debug.log"))
|
||||
FS::CreateFile("ux0:data/VITAHomebrewSorter/debug.log");
|
||||
|
@ -66,12 +66,15 @@ namespace Textures {
|
||||
}
|
||||
|
||||
bool Init(void) {
|
||||
icons.resize(2);
|
||||
icons.resize(3);
|
||||
|
||||
bool ret = Textures::LoadImagePNG("app0:res/app.png", &icons[0]);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
ret = Textures::LoadImagePNG("app0:res/folder.png", &icons[1]);
|
||||
ret = Textures::LoadImagePNG("app0:res/db.png", &icons[1]);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
ret = Textures::LoadImagePNG("app0:res/folder.png", &icons[2]);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
ret = Textures::LoadImagePNG("app0:res/splashscreen.png", &splash);
|
||||
@ -81,8 +84,9 @@ namespace Textures {
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
glDeleteTextures(1, &icons[0].id);
|
||||
glDeleteTextures(1, &icons[1].id);
|
||||
glDeleteTextures(1, &splash.id);
|
||||
glDeleteTextures(1, &icons[2].id);
|
||||
glDeleteTextures(1, &icons[1].id);
|
||||
glDeleteTextures(1, &icons[0].id);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <psp2/apputil.h>
|
||||
#include <psp2/kernel/clib.h>
|
||||
#include <psp2/common_dialog.h>
|
||||
#include <psp2/system_param.h>
|
||||
#include <psp2/rtc.h>
|
||||
#include <psp2/kernel/clib.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include "log.h"
|
||||
@ -86,4 +86,51 @@ namespace Utils {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetDateFormat(void) {
|
||||
int format = 0, ret = 0;
|
||||
|
||||
if (R_FAILED(ret = sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_DATE_FORMAT, &format))) {
|
||||
Log::Error("sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_DATE_FORMAT) failed: 0x%lx\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
// From VitaShell by TheOfficialFloW -> https://github.com/TheOfficialFloW/VitaShell/blob/master/utils.c#L349
|
||||
static void ConvertLocalTimeToUTC(SceDateTime *time_utc, SceDateTime *time_local) {
|
||||
// sceRtcGetTick and other sceRtc functions fails with year > 9999
|
||||
int year_local = time_local->year;
|
||||
int year_delta = year_local < 9999 ? 0 : year_local - 9998;
|
||||
time_local->year -= year_delta;
|
||||
|
||||
SceRtcTick tick;
|
||||
sceRtcGetTick(time_local, &tick);
|
||||
time_local->year = year_local;
|
||||
|
||||
sceRtcConvertLocalTimeToUtc(&tick, &tick);
|
||||
sceRtcSetTick(time_utc, &tick);
|
||||
time_utc->year += year_delta;
|
||||
}
|
||||
|
||||
// From VitaShell by TheOfficialFloW -> https://github.com/TheOfficialFloW/VitaShell/blob/master/utils.c#L364
|
||||
void GetDateString(char string[24], SceSystemParamDateFormat format, SceDateTime *time) {
|
||||
SceDateTime local_time;
|
||||
Utils::ConvertLocalTimeToUTC(&local_time, time);
|
||||
|
||||
switch (format) {
|
||||
case SCE_SYSTEM_PARAM_DATE_FORMAT_YYYYMMDD:
|
||||
std::snprintf(string, 24, "%04d/%02d/%02d", local_time.year, local_time.month, local_time.day);
|
||||
break;
|
||||
|
||||
case SCE_SYSTEM_PARAM_DATE_FORMAT_DDMMYYYY:
|
||||
std::snprintf(string, 24, "%02d/%02d/%04d", local_time.day, local_time.month, local_time.year);
|
||||
break;
|
||||
|
||||
case SCE_SYSTEM_PARAM_DATE_FORMAT_MMDDYYYY:
|
||||
std::snprintf(string, 24, "%02d/%02d/%04d", local_time.month, local_time.day, local_time.year);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user