mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
UI: Add a very simplistic search to game browser.
For now, no real UI (which might include a search icon, no matches message, banner that you're searching, etc.) Press Ctrl-F to filter.
This commit is contained in:
parent
ce0324b611
commit
19b15de2d5
@ -429,6 +429,9 @@ void GameButton::Draw(UIContext &dc) {
|
||||
|
||||
std::string GameButton::DescribeText() const {
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(nullptr, gamePath_, 0);
|
||||
if (ginfo->pending)
|
||||
return "...";
|
||||
|
||||
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
|
||||
return ReplaceAll(u->T("%1 button"), "%1", ginfo->GetTitle());
|
||||
}
|
||||
@ -528,6 +531,67 @@ void GameBrowser::SetPath(const Path &path) {
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void GameBrowser::ApplySearchFilter(const std::string &filter) {
|
||||
searchFilter_ = filter;
|
||||
std::transform(searchFilter_.begin(), searchFilter_.end(), searchFilter_.begin(), tolower);
|
||||
|
||||
// We don't refresh because game info loads asynchronously anyway.
|
||||
ApplySearchFilter();
|
||||
}
|
||||
|
||||
void GameBrowser::ApplySearchFilter() {
|
||||
if (searchFilter_.empty() && searchStates_.empty()) {
|
||||
// We haven't hidden anything, and we're not searching, so do nothing.
|
||||
searchPending_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
searchPending_ = false;
|
||||
// By default, everything is matching.
|
||||
searchStates_.resize(gameList_->GetNumSubviews(), SearchState::MATCH);
|
||||
|
||||
if (searchFilter_.empty()) {
|
||||
// Just quickly mark anything we hid as visible again.
|
||||
for (int i = 0; i < gameList_->GetNumSubviews(); ++i) {
|
||||
UI::View *v = gameList_->GetViewByIndex(i);
|
||||
if (searchStates_[i] != SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
}
|
||||
|
||||
searchStates_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gameList_->GetNumSubviews(); ++i) {
|
||||
UI::View *v = gameList_->GetViewByIndex(i);
|
||||
std::string label = v->DescribeText();
|
||||
// TODO: Maybe we should just save the gameButtons list, though nice to search dirs too?
|
||||
// This is a bit of a hack to recognize a pending game title.
|
||||
if (label == "...") {
|
||||
searchPending_ = true;
|
||||
// Hide anything pending while, we'll pop-in search results as they match.
|
||||
// Note: we leave it at MATCH if gone before, so we don't show it again.
|
||||
if (v->GetVisibility() == UI::V_VISIBLE) {
|
||||
if (searchStates_[i] == SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates_[i] = SearchState::PENDING;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::transform(label.begin(), label.end(), label.begin(), tolower);
|
||||
bool match = v->CanBeFocused() && label.find(searchFilter_) != label.npos;
|
||||
if (match && searchStates_[i] != SearchState::MATCH) {
|
||||
// It was previously visible and force hidden, so show it again.
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
searchStates_[i] = SearchState::MATCH;
|
||||
} else if (!match && searchStates_[i] == SearchState::MATCH && v->GetVisibility() == UI::V_VISIBLE) {
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates_[i] = SearchState::MISMATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn GameBrowser::LayoutChange(UI::EventParams &e) {
|
||||
*gridStyle_ = e.a == 0 ? true : false;
|
||||
Refresh();
|
||||
@ -622,6 +686,9 @@ void GameBrowser::Update() {
|
||||
if (listingPending_ && path_.IsListingReady()) {
|
||||
Refresh();
|
||||
}
|
||||
if (searchPending_) {
|
||||
ApplySearchFilter();
|
||||
}
|
||||
}
|
||||
|
||||
void GameBrowser::Draw(UIContext &dc) {
|
||||
@ -686,6 +753,7 @@ void GameBrowser::Refresh() {
|
||||
|
||||
// Kill all the contents
|
||||
Clear();
|
||||
searchStates_.clear();
|
||||
|
||||
Add(new Spacer(1.0f));
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
@ -1219,6 +1287,27 @@ void MainScreen::CreateViews() {
|
||||
}
|
||||
}
|
||||
|
||||
bool MainScreen::key(const KeyInput &touch) {
|
||||
if (touch.flags & KEY_DOWN) {
|
||||
if (touch.keyCode == NKCODE_CTRL_LEFT || touch.keyCode == NKCODE_CTRL_RIGHT)
|
||||
searchKeyModifier_ = true;
|
||||
if (touch.keyCode == NKCODE_F && searchKeyModifier_) {
|
||||
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__)
|
||||
auto se = GetI18NCategory(I18NCat::SEARCH);
|
||||
System_InputBoxGetString(se->T("Search term"), searchFilter_, [&](const std::string &value, int) {
|
||||
searchFilter_ = StripSpaces(value);
|
||||
searchChanged_ = true;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
} else if (touch.flags & KEY_UP) {
|
||||
if (touch.keyCode == NKCODE_CTRL_LEFT || touch.keyCode == NKCODE_CTRL_RIGHT)
|
||||
searchKeyModifier_ = false;
|
||||
}
|
||||
|
||||
return UIScreenWithBackground::key(touch);
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnAllowStorage(UI::EventParams &e) {
|
||||
System_AskForPermission(SYSTEM_PERMISSION_STORAGE);
|
||||
return UI::EVENT_DONE;
|
||||
@ -1276,6 +1365,12 @@ void MainScreen::sendMessage(const char *message, const char *value) {
|
||||
void MainScreen::update() {
|
||||
UIScreen::update();
|
||||
UpdateUIState(UISTATE_MENU);
|
||||
|
||||
if (searchChanged_) {
|
||||
for (auto browser : gameBrowsers_)
|
||||
browser->ApplySearchFilter(searchFilter_);
|
||||
searchChanged_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) {
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
|
||||
void FocusGame(const Path &gamePath);
|
||||
void SetPath(const Path &path);
|
||||
void ApplySearchFilter(const std::string &filter);
|
||||
void Draw(UIContext &dc) override;
|
||||
void Update() override;
|
||||
|
||||
@ -58,6 +59,7 @@ protected:
|
||||
virtual bool DisplayTopBar();
|
||||
virtual bool HasSpecialFiles(std::vector<Path> &filenames);
|
||||
virtual Path HomePath();
|
||||
void ApplySearchFilter();
|
||||
|
||||
void Refresh();
|
||||
|
||||
@ -80,14 +82,23 @@ private:
|
||||
UI::EventReturn OnRecentClear(UI::EventParams &e);
|
||||
UI::EventReturn OnHomebrewStore(UI::EventParams &e);
|
||||
|
||||
enum class SearchState {
|
||||
MATCH,
|
||||
MISMATCH,
|
||||
PENDING,
|
||||
};
|
||||
|
||||
UI::ViewGroup *gameList_ = nullptr;
|
||||
PathBrowser path_;
|
||||
bool *gridStyle_ = nullptr;
|
||||
BrowseFlags browseFlags_;
|
||||
std::string lastText_;
|
||||
std::string lastLink_;
|
||||
std::string searchFilter_;
|
||||
std::vector<SearchState> searchStates_;
|
||||
Path focusGamePath_;
|
||||
bool listingPending_ = false;
|
||||
bool searchPending_ = false;
|
||||
float lastScale_ = 1.0f;
|
||||
bool lastLayoutWasGrid_ = true;
|
||||
ScreenManager *screenManager_;
|
||||
@ -107,6 +118,8 @@ public:
|
||||
// Horrible hack to show the demos & homebrew tab after having installed a game from a zip file.
|
||||
static bool showHomebrewTab;
|
||||
|
||||
bool key(const KeyInput &touch) override;
|
||||
|
||||
protected:
|
||||
void CreateViews() override;
|
||||
void DrawBackground(UIContext &dc) override;
|
||||
@ -148,6 +161,9 @@ protected:
|
||||
bool lastVertical_;
|
||||
bool confirmedTemporary_ = false;
|
||||
UI::ScrollView *scrollAllGames_ = nullptr;
|
||||
bool searchKeyModifier_ = false;
|
||||
bool searchChanged_ = false;
|
||||
std::string searchFilter_;
|
||||
|
||||
friend class RemoteISOBrowseScreen;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user