mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Move more of the search code out of GameBrowser
This commit is contained in:
@@ -558,122 +558,12 @@ bool GameBrowser::Key(const KeyInput &input) {
|
|||||||
return search_.Key(gameList_, input);
|
return search_.Key(gameList_, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SearchEngine::Key(UI::ViewGroup *viewGroup, const KeyInput &input) {
|
|
||||||
bool retval = false;
|
|
||||||
// Only one is visible at a time, so we can just grab all Char input.
|
|
||||||
if (input.flags & KeyInputFlags::CHAR) {
|
|
||||||
const int unichar = input.keyCode;
|
|
||||||
if (unichar >= 0x20) {
|
|
||||||
// TODO: Save focus state here.
|
|
||||||
|
|
||||||
// Insert it! (todo: do it with a string insert)
|
|
||||||
char buf[8];
|
|
||||||
buf[u8_wc_toutf8(buf, unichar)] = '\0';
|
|
||||||
searchFilter += buf;
|
|
||||||
ApplySearchFilter(viewGroup, true);
|
|
||||||
retval = true;
|
|
||||||
}
|
|
||||||
} else if (input.flags & KeyInputFlags::DOWN) {
|
|
||||||
if (input.keyCode == NKCODE_DEL) {
|
|
||||||
if (!searchFilter.empty()) {
|
|
||||||
searchFilter.pop_back();
|
|
||||||
ApplySearchFilter(viewGroup, true);
|
|
||||||
retval = true;
|
|
||||||
if (searchFilter.empty()) {
|
|
||||||
// TODO: Restore focus state here.
|
|
||||||
UI::EnableFocusMovement(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Empty search filter. Navigate upwards on backspace?
|
|
||||||
}
|
|
||||||
} else if (!searchFilter.empty() && input.keyCode == NKCODE_ESCAPE) {
|
|
||||||
searchFilter.clear();
|
|
||||||
ApplySearchFilter(viewGroup, false);
|
|
||||||
retval = true;
|
|
||||||
|
|
||||||
// TODO: Restore focus state here.
|
|
||||||
UI::EnableFocusMovement(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBrowser::SetSearchFilter(const std::string &filter, bool setKeyboardFocus) {
|
void GameBrowser::SetSearchFilter(const std::string &filter, bool setKeyboardFocus) {
|
||||||
search_.searchFilter = filter;
|
search_.searchFilter = filter;
|
||||||
// We don't refresh because game info loads asynchronously anyway.
|
// We don't refresh because game info loads asynchronously anyway.
|
||||||
search_.ApplySearchFilter(gameList_, setKeyboardFocus);
|
search_.ApplySearchFilter(gameList_, setKeyboardFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus) {
|
|
||||||
if (searchBar) {
|
|
||||||
searchBar->SetSearchFilter(searchFilter);
|
|
||||||
searchBar->SetVisibility(searchFilter.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchFilter.empty() && searchStates.empty()) {
|
|
||||||
// We haven't hidden anything, and we're not searching, so do nothing.
|
|
||||||
searchPending = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string filter = NormalizeForSearch(searchFilter);
|
|
||||||
|
|
||||||
searchPending = false;
|
|
||||||
// By default, everything is matching.
|
|
||||||
searchStates.resize(viewGroup->GetNumSubviews(), SearchState::MATCH);
|
|
||||||
if (filter.empty()) {
|
|
||||||
// Just quickly mark anything we hid as visible again.
|
|
||||||
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
|
||||||
UI::View *v = viewGroup->GetViewByIndex(i);
|
|
||||||
if (searchStates[i] != SearchState::MATCH)
|
|
||||||
v->SetVisibility(UI::V_VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchStates.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UI::View *firstMatch = nullptr;
|
|
||||||
|
|
||||||
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
|
||||||
UI::View *v = viewGroup->GetViewByIndex(i);
|
|
||||||
std::string label = v->DescribeText();
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
label = NormalizeForSearch(label);
|
|
||||||
bool match = v->CanBeFocused() && label.find(filter) != label.npos;
|
|
||||||
if (match && !firstMatch) {
|
|
||||||
firstMatch = v;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstMatch) {
|
|
||||||
if (setKeyboardFocus) {
|
|
||||||
UI::EnableFocusMovement(true);
|
|
||||||
}
|
|
||||||
UI::SetFocusedView(firstMatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBrowser::LayoutChange(UI::EventParams &e) {
|
void GameBrowser::LayoutChange(UI::EventParams &e) {
|
||||||
*gridStyle_ = e.a == 0 ? true : false;
|
*gridStyle_ = e.a == 0 ? true : false;
|
||||||
Refresh();
|
Refresh();
|
||||||
|
|||||||
+1
-17
@@ -24,22 +24,6 @@ enum class BrowseFlags {
|
|||||||
};
|
};
|
||||||
ENUM_CLASS_BITOPS(BrowseFlags);
|
ENUM_CLASS_BITOPS(BrowseFlags);
|
||||||
|
|
||||||
enum class SearchState {
|
|
||||||
MATCH,
|
|
||||||
MISMATCH,
|
|
||||||
PENDING,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SearchEngine {
|
|
||||||
SearchBar *searchBar;
|
|
||||||
std::string searchFilter;
|
|
||||||
std::vector<SearchState> searchStates;
|
|
||||||
bool searchPending;
|
|
||||||
|
|
||||||
void ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus);
|
|
||||||
bool Key(UI::ViewGroup *viewGroup, const KeyInput &input);
|
|
||||||
};
|
|
||||||
|
|
||||||
class GameBrowser : public UI::LinearLayout {
|
class GameBrowser : public UI::LinearLayout {
|
||||||
public:
|
public:
|
||||||
GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams = nullptr);
|
GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams = nullptr);
|
||||||
@@ -97,7 +81,7 @@ private:
|
|||||||
std::string lastText_;
|
std::string lastText_;
|
||||||
std::string lastLink_;
|
std::string lastLink_;
|
||||||
|
|
||||||
SearchEngine search_{};
|
ViewSearch search_{};
|
||||||
|
|
||||||
Path focusGamePath_;
|
Path focusGamePath_;
|
||||||
bool listingPending_ = false;
|
bool listingPending_ = false;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include "Common/Data/Text/I18n.h"
|
#include "Common/Data/Text/I18n.h"
|
||||||
#include "Common/Math/curves.h"
|
#include "Common/Math/curves.h"
|
||||||
#include "Common/StringUtils.h"
|
#include "Common/StringUtils.h"
|
||||||
|
#include "Common/Data/Encoding/Utf8.h"
|
||||||
|
#include "Common/UI/Root.h"
|
||||||
#include "UI/MiscViews.h"
|
#include "UI/MiscViews.h"
|
||||||
#include "UI/GameInfoCache.h"
|
#include "UI/GameInfoCache.h"
|
||||||
#include "Common/UI/PopupScreens.h"
|
#include "Common/UI/PopupScreens.h"
|
||||||
@@ -350,3 +352,113 @@ bool SearchBar::Touch(const TouchInput &input) {
|
|||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewSearch::ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus) {
|
||||||
|
if (searchBar) {
|
||||||
|
searchBar->SetSearchFilter(searchFilter);
|
||||||
|
searchBar->SetVisibility(searchFilter.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchFilter.empty() && searchStates.empty()) {
|
||||||
|
// We haven't hidden anything, and we're not searching, so do nothing.
|
||||||
|
searchPending = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filter = NormalizeForSearch(searchFilter);
|
||||||
|
|
||||||
|
searchPending = false;
|
||||||
|
// By default, everything is matching.
|
||||||
|
searchStates.resize(viewGroup->GetNumSubviews(), SearchState::MATCH);
|
||||||
|
if (filter.empty()) {
|
||||||
|
// Just quickly mark anything we hid as visible again.
|
||||||
|
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
||||||
|
UI::View *v = viewGroup->GetViewByIndex(i);
|
||||||
|
if (searchStates[i] != SearchState::MATCH)
|
||||||
|
v->SetVisibility(UI::V_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchStates.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::View *firstMatch = nullptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
||||||
|
UI::View *v = viewGroup->GetViewByIndex(i);
|
||||||
|
std::string label = v->DescribeText();
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
label = NormalizeForSearch(label);
|
||||||
|
bool match = v->CanBeFocused() && label.find(filter) != label.npos;
|
||||||
|
if (match && !firstMatch) {
|
||||||
|
firstMatch = v;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstMatch) {
|
||||||
|
if (setKeyboardFocus) {
|
||||||
|
UI::EnableFocusMovement(true);
|
||||||
|
}
|
||||||
|
UI::SetFocusedView(firstMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewSearch::Key(UI::ViewGroup *viewGroup, const KeyInput &input) {
|
||||||
|
bool retval = false;
|
||||||
|
// Only one is visible at a time, so we can just grab all Char input.
|
||||||
|
if (input.flags & KeyInputFlags::CHAR) {
|
||||||
|
const int unichar = input.keyCode;
|
||||||
|
if (unichar >= 0x20) {
|
||||||
|
// TODO: Save focus state here.
|
||||||
|
|
||||||
|
// Insert it! (todo: do it with a string insert)
|
||||||
|
char buf[8];
|
||||||
|
buf[u8_wc_toutf8(buf, unichar)] = '\0';
|
||||||
|
searchFilter += buf;
|
||||||
|
ApplySearchFilter(viewGroup, true);
|
||||||
|
retval = true;
|
||||||
|
}
|
||||||
|
} else if (input.flags & KeyInputFlags::DOWN) {
|
||||||
|
if (input.keyCode == NKCODE_DEL) {
|
||||||
|
if (!searchFilter.empty()) {
|
||||||
|
searchFilter.pop_back();
|
||||||
|
ApplySearchFilter(viewGroup, true);
|
||||||
|
retval = true;
|
||||||
|
if (searchFilter.empty()) {
|
||||||
|
// TODO: Restore focus state here.
|
||||||
|
UI::EnableFocusMovement(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Empty search filter. Navigate upwards on backspace?
|
||||||
|
}
|
||||||
|
} else if (!searchFilter.empty() && input.keyCode == NKCODE_ESCAPE) {
|
||||||
|
searchFilter.clear();
|
||||||
|
ApplySearchFilter(viewGroup, false);
|
||||||
|
retval = true;
|
||||||
|
|
||||||
|
// TODO: Restore focus state here.
|
||||||
|
UI::EnableFocusMovement(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,3 +115,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string searchFilter_ = "N/A";
|
std::string searchFilter_ = "N/A";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SearchState {
|
||||||
|
MATCH,
|
||||||
|
MISMATCH,
|
||||||
|
PENDING,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ViewSearch {
|
||||||
|
SearchBar *searchBar;
|
||||||
|
std::string searchFilter;
|
||||||
|
std::vector<SearchState> searchStates;
|
||||||
|
bool searchPending;
|
||||||
|
|
||||||
|
void ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus);
|
||||||
|
bool Key(UI::ViewGroup *viewGroup, const KeyInput &input);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user