From 4ed419d4d5067e7c8000baad6df853c834f15b24 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Dec 2013 22:39:35 -0800 Subject: [PATCH 1/5] Support pinning paths in the game browser. For example, you might have games in multiple places, internal and external storage, or a projects directory in addition to regular games, etc. --- Core/Config.cpp | 16 ++++++- Core/Config.h | 1 + UI/MainScreen.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index b28c89bb6..1bfa83571 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -131,6 +131,12 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } } + auto pinnedPaths = iniFile.GetOrCreateSection("PinnedPaths")->ToMap(); + vPinnedPaths.clear(); + for (auto it = pinnedPaths.begin(), end = pinnedPaths.end(); it != end; ++it) { + vPinnedPaths.push_back(it->second); + } + IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); #ifdef IOS cpu->Get("Jit", &bJit, iosCanUseJit); @@ -464,6 +470,14 @@ void Config::Save() { } } + IniFile::Section *pinnedPaths = iniFile.GetOrCreateSection("PinnedPaths"); + pinnedPaths->Clear(); + for (size_t i = 0; i < vPinnedPaths.size(); ++i) { + char keyName[64]; + snprintf(keyName, sizeof(keyName), "Path%d", i); + pinnedPaths->Set(keyName, vPinnedPaths[i]); + } + IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); cpu->Set("Jit", bJit); cpu->Set("SeparateCPUThread", bSeparateCPUThread); @@ -804,4 +818,4 @@ void Config::ResetControlLayout() { g_Config.fAnalogStickX = -1.0; g_Config.fAnalogStickY = -1.0; g_Config.fAnalogStickScale = defaultScale; -} \ No newline at end of file +} diff --git a/Core/Config.h b/Core/Config.h index 63bf3d088..50b1eb95a 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -74,6 +74,7 @@ public: bool bAutoSaveSymbolMap; std::string sReportHost; std::vector recentIsos; + std::vector vPinnedPaths; std::string sLanguageIni; diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index f154c290b..0ba3192ba 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -263,10 +263,25 @@ enum GameBrowserFlags { class DirButton : public UI::Button { public: - DirButton(std::string path, UI::LayoutParams *layoutParams) - : UI::Button(path, layoutParams) {} + DirButton(const std::string &path, UI::LayoutParams *layoutParams) + : UI::Button(path, layoutParams), path_(path), absolute_(false) {} + DirButton(const std::string &path, const std::string &text, LayoutParams *layoutParams = 0) + : UI::Button(text, layoutParams), path_(path), absolute_(true) {} virtual void Draw(UIContext &dc); + + const std::string GetPath() const { + return path_; + } + + bool PathAbsolute() const { + return absolute_; + } + +private: + + std::string path_; + bool absolute_; }; void DirButton::Draw(UIContext &dc) { @@ -325,6 +340,9 @@ public: UI::Choice *HomebrewStoreButton() { return homebrewStoreButton_; } private: void Refresh(); + bool IsCurrentPathPinned(); + const std::vector GetPinnedPaths(); + const std::string GetBaseName(const std::string &path); UI::EventReturn GameButtonClick(UI::EventParams &e); UI::EventReturn GameButtonHoldClick(UI::EventParams &e); @@ -332,6 +350,7 @@ private: UI::EventReturn LayoutChange(UI::EventParams &e); UI::EventReturn LastClick(UI::EventParams &e); UI::EventReturn HomeClick(UI::EventParams &e); + UI::EventReturn PinToggleClick(UI::EventParams &e); UI::ViewGroup *gameList_; PathBrowser path_; @@ -387,6 +406,17 @@ UI::EventReturn GameBrowser::HomeClick(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn GameBrowser::PinToggleClick(UI::EventParams &e) { + auto &pinnedPaths = g_Config.vPinnedPaths; + if (IsCurrentPathPinned()) { + pinnedPaths.erase(std::remove(pinnedPaths.begin(), pinnedPaths.end(), path_.GetPath()), pinnedPaths.end()); + } else { + pinnedPaths.push_back(path_.GetPath()); + } + Refresh(); + return UI::EVENT_DONE; +} + void GameBrowser::Refresh() { using namespace UI; @@ -431,7 +461,7 @@ void GameBrowser::Refresh() { Add(gameList_); // Find games in the current directory and create new ones. - std::vector dirButtons; + std::vector dirButtons; std::vector gameButtons; if (path_.GetPath() == "!RECENT") { @@ -475,6 +505,13 @@ void GameBrowser::Refresh() { if (allowBrowsing_) { gameList_->Add(new DirButton("..", new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> OnClick.Handle(this, &GameBrowser::NavigateClick); + + // Add any pinned paths before other directories. + auto pinnedPaths = GetPinnedPaths(); + for (auto it = pinnedPaths.begin(), end = pinnedPaths.end(); it != end; ++it) { + gameList_->Add(new DirButton(*it, GetBaseName(*it), new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> + OnClick.Handle(this, &GameBrowser::NavigateClick); + } } for (size_t i = 0; i < dirButtons.size(); i++) { @@ -487,6 +524,16 @@ void GameBrowser::Refresh() { b->OnHoldClick.Handle(this, &GameBrowser::GameButtonHoldClick); } + // Show a button to toggle pinning at the very end. + if (allowBrowsing_) { + std::string caption = IsCurrentPathPinned() ? "-" : "+"; + if (!*gridStyle_) { + caption = IsCurrentPathPinned() ? "Unpin" : "Pin"; + } + gameList_->Add(new UI::Button(caption, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> + OnClick.Handle(this, &GameBrowser::PinToggleClick); + } + if (g_Config.bHomebrewStore && (flags_ & FLAG_HOMEBREWSTOREBUTTON)) { Add(new Spacer()); homebrewStoreButton_ = Add(new Choice(m->T("DownloadFromStore", "Download from the PPSSPP Homebrew Store"), new UI::LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT))); @@ -500,6 +547,62 @@ void GameBrowser::Refresh() { } } +bool GameBrowser::IsCurrentPathPinned() { + const auto paths = g_Config.vPinnedPaths; + return std::find(paths.begin(), paths.end(), path_.GetPath()) != paths.end(); +} + +const std::vector GameBrowser::GetPinnedPaths() { +#ifdef _WIN32 + static const std::string sepChars = "/"; +#else + static const std::string sepChars = "/\\"; +#endif + + const std::string currentPath = path_.GetPath(); + const std::vector paths = g_Config.vPinnedPaths; + std::vector results; + for (size_t i = 0; i < paths.size(); ++i) { + // We want to exclude the current path, and its direct children. + if (paths[i] == currentPath) { + continue; + } + if (startsWith(paths[i], currentPath)) { + std::string descendant = paths[i].substr(currentPath.size()); + // If there's only one separator (or none), its a direct child. + if (descendant.find_last_of(sepChars) == descendant.find_first_of(sepChars)) { + continue; + } + } + + results.push_back(paths[i]); + } + return results; +} + +const std::string GameBrowser::GetBaseName(const std::string &path) { +#ifdef _WIN32 + static const std::string sepChars = "/"; +#else + static const std::string sepChars = "/\\"; +#endif + + auto trailing = path.find_last_not_of(sepChars); + if (trailing != path.npos) { + size_t start = path.find_last_of(sepChars, trailing); + if (start != path.npos) { + return path.substr(start + 1, trailing - start); + } + return path.substr(0, trailing); + } + + size_t start = path.find_last_of(sepChars); + if (start != path.npos) { + return path.substr(start + 1); + } + return path; +} + UI::EventReturn GameBrowser::GameButtonClick(UI::EventParams &e) { GameButton *button = static_cast(e.v); UI::EventParams e2; @@ -519,9 +622,13 @@ UI::EventReturn GameBrowser::GameButtonHoldClick(UI::EventParams &e) { } UI::EventReturn GameBrowser::NavigateClick(UI::EventParams &e) { - UI::Button *button = static_cast(e.v); - std::string text = button->GetText(); - path_.Navigate(text); + DirButton *button = static_cast(e.v); + std::string text = button->GetPath(); + if (button->PathAbsolute()) { + path_.SetPath(text); + } else { + path_.Navigate(text); + } g_Config.currentDirectory = path_.GetPath(); Refresh(); return UI::EVENT_DONE; From 11f676d176a6f09e1999e24feef8030be1cbb9e3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Dec 2013 22:54:23 -0800 Subject: [PATCH 2/5] Support extracted ISOs (for debugging) in browser. --- UI/MainScreen.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 0ba3192ba..b00bf034b 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -472,8 +472,14 @@ void GameBrowser::Refresh() { std::vector fileInfo; path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:"); for (size_t i = 0; i < fileInfo.size(); i++) { - if (fileInfo[i].isDirectory && (path_.GetPath().size() < 4 || !File::Exists(path_.GetPath() + fileInfo[i].name + "/EBOOT.PBP"))) { - // Check if eboot directory + bool isGame = !fileInfo[i].isDirectory; + // Check if eboot directory + if (!isGame && path_.GetPath().size() >= 4 && File::Exists(path_.GetPath() + fileInfo[i].name + "/EBOOT.PBP")) + isGame = true; + else if (!isGame && File::Exists(path_.GetPath() + fileInfo[i].name + "/PSP_GAME/SYSDIR")) + isGame = true; + + if (!isGame) { if (allowBrowsing_) { dirButtons.push_back(new DirButton(fileInfo[i].name, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); } From ae576f245787ddef8e4ae7493cf6a4a8b165c3ea Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Dec 2013 22:48:12 -0800 Subject: [PATCH 3/5] Show the path in the game details screen. Helps when you have 2+ isos in the same dir with different versions of the same game, heh. Like when hacking/translating. --- UI/GameScreen.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 8dde8d431..3fa1326c7 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -54,11 +54,13 @@ void GameScreen::CreateViews() { leftColumn->Add(new Choice(d->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &GameScreen::OnSwitchBack); if (info) { texvGameIcon_ = leftColumn->Add(new TextureView(0, IS_DEFAULT, new AnchorLayoutParams(144 * 2, 80 * 2, 10, 10, NONE, NONE))); - tvTitle_ = leftColumn->Add(new TextView(info->title, ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 200, NONE, NONE))); - tvGameSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 250, NONE, NONE))); - tvSaveDataSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 290, NONE, NONE))); - tvInstallDataSize_ = leftColumn->Add(new TextView("", ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 330, NONE, NONE))); - tvRegion_ = leftColumn->Add(new TextView("", ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 370, NONE, NONE))); + tvTitle_ = leftColumn->Add(new TextView(info->title, ALIGN_LEFT, false, new AnchorLayoutParams(10, 200, NONE, NONE))); + // This one doesn't need to be updated. + leftColumn->Add(new TextView(gamePath_, ALIGN_LEFT, true, new AnchorLayoutParams(10, 250, NONE, NONE))); + tvGameSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, true, new AnchorLayoutParams(10, 290, NONE, NONE))); + tvSaveDataSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, true, new AnchorLayoutParams(10, 320, NONE, NONE))); + tvInstallDataSize_ = leftColumn->Add(new TextView("", ALIGN_LEFT, true, new AnchorLayoutParams(10, 350, NONE, NONE))); + tvRegion_ = leftColumn->Add(new TextView("", ALIGN_LEFT, true, new AnchorLayoutParams(10, 380, NONE, NONE))); } ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); From 4bc86afd5edf34bdc1cdac470f17fce9c8a1c9a0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Dec 2013 22:58:01 -0800 Subject: [PATCH 4/5] Adjust some project filters. --- GPU/GPU.vcxproj.filters | 8 ++++++-- headless/Headless.vcxproj | 1 + headless/Headless.vcxproj.filters | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index a6657c2a6..b019c2265 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -296,8 +296,12 @@ Common - - + + GLES + + + GLES + diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 238aa92be..83060a748 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -202,6 +202,7 @@ + diff --git a/headless/Headless.vcxproj.filters b/headless/Headless.vcxproj.filters index 4c94420ef..bb8ca8712 100644 --- a/headless/Headless.vcxproj.filters +++ b/headless/Headless.vcxproj.filters @@ -10,6 +10,7 @@ + From 1513701d0ef8935f4fa0748cec7d3fb577b86f8f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Dec 2013 23:02:29 -0800 Subject: [PATCH 5/5] Oops, make things translatable. --- UI/MainScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index b00bf034b..d820bb6f8 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -534,7 +534,7 @@ void GameBrowser::Refresh() { if (allowBrowsing_) { std::string caption = IsCurrentPathPinned() ? "-" : "+"; if (!*gridStyle_) { - caption = IsCurrentPathPinned() ? "Unpin" : "Pin"; + caption = IsCurrentPathPinned() ? m->T("UnpinPath", "Unpin") : m->T("PinPath", "Pin"); } gameList_->Add(new UI::Button(caption, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> OnClick.Handle(this, &GameBrowser::PinToggleClick);