applist: Add option to sort by Title IDs

This commit is contained in:
Joel16 2021-04-20 14:34:45 -04:00
parent cd566bf3c1
commit 19ff15c4e6
3 changed files with 72 additions and 59 deletions

View File

@ -4,7 +4,7 @@
#include <vector>
#include <string>
typedef struct AppInfoIcon {
struct AppInfoIcon {
int pageId = 0;
int pageNo = 0;
int pos = 0;
@ -12,24 +12,32 @@ typedef struct AppInfoIcon {
char titleId[16];
int reserved01 = 0;
bool folder = false;
} AppInfoIcon;
};
typedef struct AppInfoPage {
struct AppInfoPage {
int pageId = 0;
int pageNo = 0;
} AppInfoPage;
};
typedef struct AppInfoFolder {
struct AppInfoFolder {
int pageId = 0;
int index = 0;
} AppInfoFolder;
};
struct AppEntries {
std::vector<AppInfoIcon> icons;
std::vector<AppInfoPage> pages;
std::vector<AppInfoFolder> folders;
};
extern int sort_mode;
namespace AppList {
int Get(std::vector<AppInfoIcon> &entries, std::vector<AppInfoPage> &pages, std::vector<AppInfoFolder> &folders);
int Get(AppEntries *entries);
int Save(std::vector<AppInfoIcon> &entries);
bool SortAlphabeticalAsc(const AppInfoIcon &entryA, const AppInfoIcon &entryB);
bool SortAlphabeticalDesc(const AppInfoIcon &entryA, const AppInfoIcon &entryB);
void Sort(std::vector<AppInfoIcon> &entries, std::vector<AppInfoPage> &pages, std::vector<AppInfoFolder> &folders);
void Sort(AppEntries *entries);
int Backup(void);
int Restore(void);
bool Compare(const char *db_name);

View File

@ -11,10 +11,10 @@
namespace AppList {
constexpr char path[] = "ur0:shell/db/app.db";
int Get(std::vector<AppInfoIcon> &entries, std::vector<AppInfoPage> &pages, std::vector<AppInfoFolder> &folders) {
entries.clear();
pages.clear();
folders.clear();
int Get(AppEntries *entries) {
entries->icons.clear();
entries->pages.clear();
entries->folders.clear();
sqlite3 *db;
int ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE, nullptr);
@ -32,16 +32,16 @@ namespace AppList {
ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr);
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) {
AppInfoIcon entry;
entry.pageId = std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
entry.pageNo = sqlite3_column_int(stmt, 1);
entry.pos = sqlite3_column_int(stmt, 2);
std::snprintf(entry.title, 128, "%s", reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
std::snprintf(entry.titleId, 16, "%s", sqlite3_column_text(stmt, 4));
if (std::string(entry.titleId) == "(null)")
entry.reserved01 = (std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5))));
entry.folder = (std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6)))) == 7? true : false;
entries.push_back(entry);
AppInfoIcon icon;
icon.pageId = std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
icon.pageNo = sqlite3_column_int(stmt, 1);
icon.pos = sqlite3_column_int(stmt, 2);
std::snprintf(icon.title, 128, "%s", reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
std::snprintf(icon.titleId, 16, "%s", sqlite3_column_text(stmt, 4));
if (std::string(icon.titleId) == "(null)")
icon.reserved01 = (std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5))));
icon.folder = (std::stoi(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6)))) == 7? true : false;
entries->icons.push_back(icon);
}
if (ret != SQLITE_DONE) {
@ -69,11 +69,11 @@ namespace AppList {
if (pageNo >= 0) {
page.pageId = sqlite3_column_int(stmt, 0);
page.pageNo = pageNo;
pages.push_back(page);
entries->pages.push_back(page);
}
else if (pageNo < 0) {
folder.pageId = sqlite3_column_int(stmt, 0);
folders.push_back(folder);
entries->folders.push_back(folder);
}
}
@ -149,8 +149,8 @@ namespace AppList {
}
bool SortAlphabeticalAsc(const AppInfoIcon &entryA, const AppInfoIcon &entryB) {
std::string entryAname = entryA.title;
std::string entryBname = entryB.title;
std::string entryAname = sort_mode == 0? entryA.title : entryA.titleId;
std::string entryBname = sort_mode == 0? entryB.title : entryB.titleId;
std::transform(entryAname.begin(), entryAname.end(), entryAname.begin(), [](unsigned char c){ return std::tolower(c); });
std::transform(entryBname.begin(), entryBname.end(), entryBname.begin(), [](unsigned char c){ return std::tolower(c); });
@ -162,8 +162,8 @@ namespace AppList {
}
bool SortAlphabeticalDesc(const AppInfoIcon &entryA, const AppInfoIcon &entryB) {
std::string entryAname = entryA.title;
std::string entryBname = entryB.title;
std::string entryAname = sort_mode == 0? entryA.title : entryA.titleId;
std::string entryBname = sort_mode == 0? entryB.title : entryB.titleId;
std::transform(entryAname.begin(), entryAname.end(), entryAname.begin(), [](unsigned char c){ return std::tolower(c); });
std::transform(entryBname.begin(), entryBname.end(), entryBname.begin(), [](unsigned char c){ return std::tolower(c); });
@ -174,9 +174,9 @@ namespace AppList {
return false;
}
void Sort(std::vector<AppInfoIcon> &entries, std::vector<AppInfoPage> &pages, std::vector<AppInfoFolder> &folders) {
void Sort(AppEntries *entries) {
int pos = 0, pageCounter = 0;
for (int i = 0; i < entries.size(); i ++) {
for (int i = 0; i < entries->icons.size(); i ++) {
// Reset position
if (pos > 9) {
pos = 0;
@ -184,17 +184,17 @@ namespace AppList {
}
// App/Game belongs to a folder
if (entries[i].pageNo < 0) {
for (int j = 0; j < folders.size(); j++) {
if (entries[i].pageId == folders[j].pageId) {
entries[i].pos = folders[j].index;
folders[j].index++;
if (entries->icons[i].pageNo < 0) {
for (int j = 0; j < entries->folders.size(); j++) {
if (entries->icons[i].pageId == entries->folders[j].pageId) {
entries->icons[i].pos = entries->folders[j].index;
entries->folders[j].index++;
}
}
}
else {
entries[i].pos = pos;
entries[i].pageId = pages[pageCounter].pageId;
entries->icons[i].pos = pos;
entries->icons[i].pageId = entries->pages[pageCounter].pageId;
pos++;
}
}

View File

@ -11,6 +11,8 @@
#include "textures.h"
#include "utils.h"
int sort_mode = 0;
namespace Renderer {
static void End(bool clear, ImVec4 clear_color) {
glViewport(0, 0, static_cast<int>(ImGui::GetIO().DisplaySize.x), static_cast<int>(ImGui::GetIO().DisplaySize.y));
@ -223,16 +225,14 @@ namespace GUI {
int RenderLoop(void) {
bool done = false;
backupExists = (FS::FileExists("ux0:/data/VITAHomebrewSorter/backup/app.db") || FS::FileExists("ux0:/data/VITAHomebrewSorter/backup/app.db.bkp"));
std::vector<AppInfoIcon> apps;
std::vector<AppInfoPage> pages;
std::vector<AppInfoFolder> folders;
AppEntries entries;
std::vector<SceIoDirent> loadouts;
int ret = AppList::Get(apps, pages, folders);
int ret = AppList::Get(&entries);
ret = FS::GetDirList("ux0:data/VITAHomebrewSorter/loadouts", loadouts);
int date_format = Utils::GetDateFormat();
std::string loadout_name;
enum SortMode {
enum SortBy {
SortDefault,
SortAsc,
SortDesc
@ -244,8 +244,8 @@ namespace GUI {
Folder
};
static SortMode sort = SortDefault;
static State state = StateNone;
SortBy sort = SortDefault;
State state = StateNone;
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter |
ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ScrollY;
@ -259,27 +259,32 @@ namespace GUI {
if (ImGui::BeginTabItem("Sort/Backup")) {
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
ImGui::SetNextItemWidth(100.0f);
ImGui::Combo("Sort by", &sort_mode, "Title\0Title ID\0");
ImGui::SameLine();
if (ImGui::RadioButton("Default", sort == SortDefault)) {
sort = SortDefault;
ret = AppList::Get(apps, pages, folders);
ret = AppList::Get(&entries);
}
ImGui::SameLine();
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);
ret = AppList::Get(&entries);
std::sort(entries.icons.begin(), entries.icons.end(), AppList::SortAlphabeticalAsc);
AppList::Sort(&entries);
}
ImGui::SameLine();
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);
ret = AppList::Get(&entries);
std::sort(entries.icons.begin(), entries.icons.end(), AppList::SortAlphabeticalDesc);
AppList::Sort(&entries);
}
ImGui::SameLine();
@ -306,26 +311,26 @@ namespace GUI {
ImGui::TableSetupColumn("Position");
ImGui::TableHeadersRow();
for (int i = 0; i < apps.size(); i++) {
for (int i = 0; i < entries.icons.size(); i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Image(reinterpret_cast<ImTextureID>(apps[i].folder? icons[Folder].id : icons[App].id), ImVec2(20, 20));
ImGui::Image(reinterpret_cast<ImTextureID>(entries.icons[i].folder? icons[Folder].id : icons[App].id), ImVec2(20, 20));
ImGui::TableNextColumn();
ImGui::Selectable(apps[i].title, false, ImGuiSelectableFlags_SpanAllColumns);
ImGui::Selectable(entries.icons[i].title, false, ImGuiSelectableFlags_SpanAllColumns);
ImGui::TableNextColumn();
ImGui::Text("%d", apps[i].pageId);
ImGui::Text("%d", entries.icons[i].pageId);
ImGui::TableNextColumn();
if (apps[i].pageNo < 0)
if (entries.icons[i].pageNo < 0)
ImGui::Text("Inside folder");
else
ImGui::Text("%d", apps[i].pageNo);
ImGui::Text("%d", entries.icons[i].pageNo);
ImGui::TableNextColumn();
ImGui::Text("%d", apps[i].pos);
ImGui::Text("%d", entries.icons[i].pos);
}
ImGui::EndTable();
@ -383,7 +388,7 @@ namespace GUI {
}
GUI::ExitWindow();
GUI::Prompt(&state, apps, loadout_name.c_str());
GUI::Prompt(&state, entries.icons, loadout_name.c_str());
Renderer::End(true, ImVec4(0.45f, 0.55f, 0.60f, 1.00f));
}