diff --git a/inc/file.h b/inc/file.h index 52f156d..30618e8 100644 --- a/inc/file.h +++ b/inc/file.h @@ -54,11 +54,7 @@ namespace fs bool pathIsFiltered(const std::string& _path); void freePathFilters(); - inline void wipeSave() - { - fs::delDir("sv:/"); - fsdevCommitDevice("sv"); - } + void wipeSave(); //Dumps all titles for 'user'. returns false to bail bool dumpAllUserSaves(const data::user& u); diff --git a/inc/fsthrd.h b/inc/fsthrd.h index 0c72e62..9d89cea 100644 --- a/inc/fsthrd.h +++ b/inc/fsthrd.h @@ -10,5 +10,6 @@ namespace fs void copyFileCommit_t(void *a); void copyDirToZip_t(void *a); void copyZipToDir_t(void *a); + void wipesave_t(void *a); void closeZip_t(void *a); } diff --git a/inc/type.h b/inc/type.h index 0748bce..9b3dd64 100644 --- a/inc/type.h +++ b/inc/type.h @@ -30,6 +30,7 @@ typedef struct { bool running = false, finished = false; Thread thrd; + ThreadFunc thrdFunc; void *argPtr = NULL; funcPtr drawFunc = NULL;//Draw func is passed threadInfo pointer too threadStatus *status; diff --git a/src/data.cpp b/src/data.cpp index 131d6b8..0d616a5 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -50,16 +50,17 @@ static struct { std::string titleA = data::getTitleNameByTID(a.saveID); std::string titleB = data::getTitleNameByTID(b.saveID); - uint32_t tmpA, tmpB; - for(unsigned i = 0; i < titleA.length(); ) + uint32_t pointA, pointB; + for(unsigned i = 0, j = 0; i < titleA.length(); ) { - 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; + ssize_t aCnt = decode_utf8(&pointA, (const uint8_t *)&titleA.data()[i]); + ssize_t bCnt = decode_utf8(&pointB, (const uint8_t *)&titleB.data()[j]); + pointA = tolower(pointA), pointB = tolower(pointB); + if(pointA != pointB) + return pointA < pointB; - i += uCnt; + i += aCnt; + j += bCnt; } } break; diff --git a/src/file.cpp b/src/file.cpp index 965400f..06f229f 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -484,6 +484,11 @@ void fs::freePathFilters() pathFilter.clear(); } +void fs::wipeSave() +{ + ui::newThread(fs::wipesave_t, NULL, NULL); +} + bool fs::dumpAllUserSaves(const data::user& u) { for(unsigned i = 0; i < u.titleInfo.size(); i++) diff --git a/src/fsthrd.cpp b/src/fsthrd.cpp index 88a3ad9..eb21570 100644 --- a/src/fsthrd.cpp +++ b/src/fsthrd.cpp @@ -267,14 +267,6 @@ void fs::copyDirToZip_t(void *a) t->finished = true; } -void fs::closeZip_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - zipFile z = t->argPtr; - zipClose(z, NULL); - t->finished = true; -} - void fs::copyZipToDir_t(void *a) { threadInfo *t = (threadInfo *)a; @@ -360,3 +352,20 @@ void fs::copyZipToDir_t(void *a) delete[] buff; t->finished = true; } + +void fs::wipesave_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + t->status->setStatus("Resetting current save..."); + fs::delDir("sv:/"); + fs::commitToDevice("sv"); + t->finished = true; +} + +void fs::closeZip_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + zipFile z = t->argPtr; + zipClose(z, NULL); + t->finished = true; +} diff --git a/src/ui.cpp b/src/ui.cpp index 561e002..ba10f6b 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -247,10 +247,9 @@ void ui::drawUI() for(slideOutPanel *s : panels) s->draw(&ui::slidePanelColor); - popMessages->draw(); + threadMngr->draw(); - if(!threadMngr->empty()) - threadMngr->draw(); + popMessages->draw(); } static bool debugDisp = false; diff --git a/src/ui/ext.cpp b/src/ui/ext.cpp index b6f1923..5dfbeaa 100644 --- a/src/ui/ext.cpp +++ b/src/ui/ext.cpp @@ -3,6 +3,7 @@ #include "ui.h" #include "file.h" +#include "util.h" ui::menu *ui::extMenu; @@ -88,10 +89,53 @@ static void extMenuOptRemoveUpdate(void *a) ui::newThread(_delUpdate, NULL, NULL); } +static void extMenuTerminateProcess(void *a) +{ + std::string idStr = util::getStringInput(SwkbdType_QWERTY, "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::showPopMessage(POP_FRAME_DEFAULT, "Process %s successfully shutdown.", idStr.c_str()); + } +} + +static void extMenuMountSysSave(void *a) +{ + FsFileSystem sys; + std::string idStr = util::getStringInput(SwkbdType_QWERTY, "8000000000000000", "Enter Sys Save ID", 18, 0, NULL); + uint64_t mountID = std::strtoull(idStr.c_str(), NULL, 16); + if(R_SUCCEEDED(fsOpen_SystemSaveData(&sys, FsSaveDataSpaceId_System, mountID, (AccountUid) {0}))) + { + fsdevMountDevice("sv", sys); + ui::fmPrep(FsSaveDataType_System, "sv:/", true); + ui::usrSelPanel->closePanel(); + ui::changeState(FIL_MDE); + } +} + +//Todo: Not so simple now. +static void extMenuReloadTitles(void *a) +{ + +} + +static void extMenuMountRomFS(void *a) +{ + FsFileSystem tromfs; + if(R_SUCCEEDED(fsOpenDataFileSystemByCurrentProcess(&tromfs))) + { + fsdevMountDevice("tromfs", tromfs); + ui::fmPrep(FsSaveDataType_System, "tromfs:/", false); + ui::usrSelPanel->closePanel(); + ui::changeState(FIL_MDE); + } +} + void ui::extInit() { ui::extMenu = new ui::menu; - ui::extMenu->setParams(200, 32, 1016, 24, 5); + ui::extMenu->setParams(200, 24, 1002, 24, 4); ui::extMenu->setCallback(extMenuCallback, NULL); ui::extMenu->setActive(false); for(unsigned i = 0; i < 11; i++) @@ -109,6 +153,14 @@ void ui::extInit() ui::extMenu->optAddButtonEvent(4, HidNpadButton_A, toFMUser, NULL); //Del update ui::extMenu->optAddButtonEvent(5, HidNpadButton_A, extMenuOptRemoveUpdate, NULL); + //Terminate Process + ui::extMenu->optAddButtonEvent(6, HidNpadButton_A, extMenuTerminateProcess, NULL); + //Mount system save + ui::extMenu->optAddButtonEvent(7, HidNpadButton_A, extMenuMountSysSave, NULL); + //Rescan + ui::extMenu->optAddButtonEvent(8, HidNpadButton_A, extMenuReloadTitles, NULL); + //RomFS + ui::extMenu->optAddButtonEvent(9, HidNpadButton_A, extMenuMountRomFS, NULL); } void ui::extExit() diff --git a/src/ui/fm.cpp b/src/ui/fm.cpp index 60ee452..74194aa 100644 --- a/src/ui/fm.cpp +++ b/src/ui/fm.cpp @@ -383,7 +383,7 @@ void ui::fmInit() devMenu = new ui::menu; devMenu->setCallback(_devMenuCallback, devArgs); - devMenu->setParams(10, 8, 590, 18, 6); + devMenu->setParams(10, 8, 590, 18, 5); devMenu->setActive(true); devArgs->b->m = devMenu; @@ -404,7 +404,7 @@ void ui::fmInit() sdMenu = new ui::menu; sdMenu->setCallback(_sdMenuCallback, sdmcArgs); - sdMenu->setParams(620, 8, 590, 18, 6); + sdMenu->setParams(620, 8, 590, 18, 5); sdMenu->setActive(false); sdmcArgs->b->m = sdMenu; diff --git a/src/ui/miscui.cpp b/src/ui/miscui.cpp index 3b1e146..227e2d2 100644 --- a/src/ui/miscui.cpp +++ b/src/ui/miscui.cpp @@ -29,7 +29,7 @@ void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& rY = _y; fSize = _fS; mL = _mL; - rH = _fS + 24; + rH = _fS + 32; } void ui::menu::editParam(int _param, unsigned newVal) @@ -73,7 +73,7 @@ int ui::menu::addOpt(SDL_Texture *_icn, const std::string& add) tmp += add.substr(i, untCnt); i += untCnt; - if((int)gfx::getTextWidth(tmp.c_str(), fSize) >= rW - 48) + if((int)gfx::getTextWidth(tmp.c_str(), fSize) >= rW - 56) { newOpt.txt = tmp; break; @@ -136,35 +136,26 @@ void ui::menu::update() if( (down & HidNpadButton_AnyUp) || ((held & HidNpadButton_AnyUp) && fc == 10) ) { if(selected > 0) - { --selected; - if(selected - mL >= 0 && selected <= mSize - mL) - tY += rH; - } } else if( (down & HidNpadButton_AnyDown) || ((held & HidNpadButton_AnyDown) && fc == 10)) { if(selected < mSize) - { ++selected; - if(selected - mL > 0 && selected + mL <= mSize + 1) - tY -= rH; - } } else if(down & HidNpadButton_AnyLeft) { - selected -= scrL / 2; + selected -= mL; if(selected < 0) selected = 0; } else if(down & HidNpadButton_AnyRight) { - selected += scrL / 2; + selected += mL; if(selected > mSize) selected = mSize; } - - if(down) + if(down && !opt[selected].events.empty()) { for(ui::menuOptEvent& e : opt[selected].events) { @@ -173,6 +164,13 @@ void ui::menu::update() } } + if(selected <= mL) + tY = mY; + else if(selected >= (mSize - mL) && mSize > mL * 2) + tY = mY + -(rH * (mSize - (mL * 2))); + else if(selected > mL && selected < (mSize - mL)) + tY = -(rH * (selected - mL)); + if(selected != oldSel && onChange) (*onChange)(NULL); @@ -209,6 +207,9 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText for(int i = 0, tY = y; i < (int)opt.size(); i++, tY += rH) { + if(tY < -rH || tY > tH) + continue; + if(i == selected) { if(isActive) @@ -220,7 +221,7 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText } else { - if(drawText && (tY > -rH || tY < tH)) + if(drawText) gfx::drawTextf(target, fSize, x + 20, (y + (rH / 2 - fSize / 2)) + (i * rH), textClr, opt[i].txt.c_str()); } diff --git a/src/ui/sett.cpp b/src/ui/sett.cpp index 37dbf0b..0bf898c 100644 --- a/src/ui/sett.cpp +++ b/src/ui/sett.cpp @@ -146,7 +146,7 @@ static void updateMenuText() void ui::settInit() { ui::settMenu = new ui::menu; - ui::settMenu->setParams(200, 32, 1016, 24, 5); + ui::settMenu->setParams(200, 24, 1002, 24, 4); ui::settMenu->setCallback(settMenuCallback, NULL); ui::settMenu->setActive(false); diff --git a/src/ui/thrdProc.cpp b/src/ui/thrdProc.cpp index 56120ea..7f4f2d4 100644 --- a/src/ui/thrdProc.cpp +++ b/src/ui/thrdProc.cpp @@ -4,7 +4,9 @@ #include "ui.h" #include "gfx.h" -//Thread status screen always using white +#include "file.h" + +//Thread status screen always uses white static const SDL_Color white = {0xFF, 0xFF, 0xFF, 0xFF}; static const SDL_Color darkenBack = {0x00, 0x00, 0x00, 0xBB}; @@ -23,36 +25,32 @@ threadInfo *ui::threadProcMngr::newThread(ThreadFunc func, void *args, funcPtr _ { threadInfo *t = new threadInfo; t->status = new threadStatus; + t->running = false; t->finished = false; + t->thrdFunc = func; t->drawFunc = _drawfunc; t->argPtr = args; - if(R_SUCCEEDED(threadCreate(&t->thrd, func, t, NULL, 0x20000, 0x2B, 1))) - { - mutexLock(&threadLock); - threads.push_back(t); - mutexUnlock(&threadLock); - return threads[threads.size() - 1]; - } - else - { - delete t->status; - delete t; - } - return NULL; + mutexLock(&threadLock); + threads.push_back(t); + mutexUnlock(&threadLock); + return threads[threads.size() - 1]; } void ui::threadProcMngr::update() { if(!threads.empty()) { + Result res = 0; threadInfo *t = threads[0]; - if(t->running == false && t->finished == false) + if(!t->running && R_SUCCEEDED((res = threadCreate(&t->thrd, t->thrdFunc, t, NULL, 0x20000, 0x2B, 1)))) { - t->running = true; threadStart(&t->thrd); + t->running = true; } - else if(t->running == true && t->finished == true) + else if(!t->running && R_FAILED(res))//Should kill the thread that failed. + t->finished = true; + else if(t->finished) { threadWaitForExit(&t->thrd); threadClose(&t->thrd); @@ -67,27 +65,32 @@ void ui::threadProcMngr::update() void ui::threadProcMngr::draw() { - if(++frameCount % 4 == 0 && ++lgFrame > 7) - lgFrame = 0; - - if(clrAdd && (clrShft += 6) >= 0x72) - clrAdd = false; - else if(!clrAdd && (clrShft -= 3) <= 0x00) - clrAdd = true; - - - SDL_Color glyphCol = {0x00, (uint8_t)(0x88 + clrShft), (uint8_t)(0xC5 + (clrShft / 2)), 0xFF}; - - gfx::drawRect(NULL, &darkenBack, 0, 0, 1280, 720); - gfx::drawTextf(NULL, 32, 56, 673, &glyphCol, loadGlyphArray[lgFrame].c_str()); - if(threads[0]->drawFunc) - (*(threads[0]->drawFunc))(threads[0]); - else + if(!threads.empty()) { - std::string gStatus; - threads[0]->status->getStatus(gStatus); + if(++frameCount % 4 == 0 && ++lgFrame > 7) + lgFrame = 0; - int statX = 640 - (gfx::getTextWidth(gStatus.c_str(), 18) / 2); - gfx::drawTextf(NULL, 18, statX, 387, &white, gStatus.c_str()); + if(clrAdd && (clrShft += 6) >= 0x72) + clrAdd = false; + else if(!clrAdd && (clrShft -= 3) <= 0x00) + clrAdd = true; + + + SDL_Color glyphCol = {0x00, (uint8_t)(0x88 + clrShft), (uint8_t)(0xC5 + (clrShft / 2)), 0xFF}; + + gfx::drawRect(NULL, &darkenBack, 0, 0, 1280, 720); + gfx::drawTextf(NULL, 32, 56, 673, &glyphCol, loadGlyphArray[lgFrame].c_str()); + + threadInfo *t = threads[0]; + if(t->drawFunc) + (*(t->drawFunc))(t); + else + { + std::string gStatus; + t->status->getStatus(gStatus); + + int statX = 640 - (gfx::getTextWidth(gStatus.c_str(), 18) / 2); + gfx::drawTextf(NULL, 18, statX, 387, &white, gStatus.c_str()); + } } } diff --git a/src/ui/usr.cpp b/src/ui/usr.cpp index 6437072..664a191 100644 --- a/src/ui/usr.cpp +++ b/src/ui/usr.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "file.h" @@ -37,6 +38,30 @@ static std::vector accSids, devSids, bcatSids, cacheSids; static unsigned usrHelpX = 0; +//Sort save create tids alphabetically by title from data +static struct +{ + bool operator()(const uint64_t& tid1, const uint64_t& tid2) + { + std::string tid1Title = data::getTitleNameByTID(tid1); + std::string tid2Title = data::getTitleNameByTID(tid2); + + uint32_t pointA = 0, pointB = 0; + for(unsigned i = 0, j = 0; i < tid1Title.length(); ) + { + ssize_t tid1Cnt = decode_utf8(&pointA, (const uint8_t *)&tid1Title.c_str()[i]); + ssize_t tid2Cnt = decode_utf8(&pointB, (const uint8_t *)&tid2Title.c_str()[j]); + + pointA = tolower(pointA), pointB = tolower(pointB); + if(pointA != pointB) + return pointA < pointB; + + i += tid1Cnt, j += tid2Cnt; + } + return false; + } +} sortCreateTIDs; + static void onMainChange(void *a) { if(ui::usrMenu->getSelected() < (int)data::users.size()) @@ -317,23 +342,23 @@ void ui::usrInit() bcatSaveMenu = new ui::menu; cacheSaveMenu = new ui::menu; - usrMenu->setParams(64, 16, 0, 96, 2); - usrOptMenu->setParams(8, 32, 390, 20, 7); + usrMenu->setParams(54, 16, 0, 106, 1); + usrOptMenu->setParams(8, 32, 390, 20, 6); usrOptMenu->setCallback(usrOptCallback, NULL); - saveCreateMenu->setParams(8, 32, 492, 20, 7); + saveCreateMenu->setParams(8, 32, 492, 20, 6); saveCreateMenu->setActive(false); saveCreateMenu->setCallback(saveCreateCallback, NULL); - deviceSaveMenu->setParams(8, 32, 492, 20, 7); + deviceSaveMenu->setParams(8, 32, 492, 20, 6); deviceSaveMenu->setActive(false); deviceSaveMenu->setCallback(saveCreateCallback, NULL); - bcatSaveMenu->setParams(8, 32, 492, 20, 7); + bcatSaveMenu->setParams(8, 32, 492, 20, 6); bcatSaveMenu->setActive(false); bcatSaveMenu->setCallback(saveCreateCallback, NULL); - cacheSaveMenu->setParams(8, 32, 492, 20, 7); + cacheSaveMenu->setParams(8, 32, 492, 20, 6); cacheSaveMenu->setActive(false); cacheSaveMenu->setCallback(saveCreateCallback, NULL); @@ -352,7 +377,7 @@ void ui::usrInit() usrMenu->optAddButtonEvent(pos, HidNpadButton_A, toEXT, NULL); usrMenu->setOnChangeFunc(onMainChange); - usrMenu->editParam(MENU_RECT_WIDTH, 126); + usrMenu->editParam(MENU_RECT_WIDTH, 136); usrSelPanel = new ui::slideOutPanel(200, 559, 89, ui::SLD_LEFT, _usrSelPanelDraw); usrSelPanel->setX(0); @@ -384,38 +409,55 @@ void ui::usrInit() devCreate = {FsSaveDataType_Device, deviceSaveMenu}; bcatCreate = {FsSaveDataType_Bcat, bcatSaveMenu}; cacheCreate = {FsSaveDataType_Cache, cacheSaveMenu}; + + //Group into vectors to match for(auto& t : data::titles) { NacpStruct *nacp = &t.second.nacp; if(nacp->user_account_save_data_size > 0) - { - int optPos = saveCreateMenu->addOpt(NULL, t.second.title); - saveCreateMenu->optAddButtonEvent(optPos, HidNpadButton_A, createSaveData, &accCreate); accSids.push_back(t.first); - } if(nacp->device_save_data_size > 0) - { - int optPos = deviceSaveMenu->addOpt(NULL, t.second.title); - deviceSaveMenu->optAddButtonEvent(optPos, HidNpadButton_A, createSaveData, &devCreate); devSids.push_back(t.first); - } if(nacp->bcat_delivery_cache_storage_size > 0) - { - int optPos = bcatSaveMenu->addOpt(NULL, t.second.title); - bcatSaveMenu->optAddButtonEvent(optPos, HidNpadButton_A, createSaveData, &bcatCreate); bcatSids.push_back(t.first); - } if(nacp->cache_storage_size > 0 || nacp->cache_storage_journal_size > 0 || nacp->cache_storage_data_and_journal_size_max > 0) - { - int optPos = cacheSaveMenu->addOpt(NULL, t.second.title); - cacheSaveMenu->optAddButtonEvent(optPos, HidNpadButton_A, createSaveData, &cacheCreate); cacheSids.push_back(t.first); - } } + + //Sort them alphabetically + std::sort(accSids.begin(), accSids.end(), sortCreateTIDs); + std::sort(devSids.begin(), devSids.end(), sortCreateTIDs); + std::sort(bcatSids.begin(), bcatSids.end(), sortCreateTIDs); + std::sort(cacheSids.begin(), cacheSids.end(), sortCreateTIDs); + + for(unsigned i = 0; i < accSids.size(); i++) + { + saveCreateMenu->addOpt(NULL, data::getTitleNameByTID(accSids[i])); + saveCreateMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &accCreate); + } + + for(unsigned i = 0; i < devSids.size(); i++) + { + deviceSaveMenu->addOpt(NULL, data::getTitleNameByTID(devSids[i])); + deviceSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &devCreate); + } + + for(unsigned i = 0; i < bcatSids.size(); i++) + { + bcatSaveMenu->addOpt(NULL, data::getTitleNameByTID(bcatSids[i])); + bcatSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &bcatCreate); + } + + for(unsigned i = 0; i < cacheSids.size(); i++) + { + cacheSaveMenu->addOpt(NULL, data::getTitleNameByTID(cacheSids[i])); + cacheSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &cacheCreate); + } + usrHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18); }