2023-06-16 11:44:35 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "Common/StringUtils.h"
|
|
|
|
#include "Common/System/NativeApp.h"
|
|
|
|
#include "Common/System/Request.h"
|
|
|
|
#include "Common/System/Display.h"
|
|
|
|
#include "UI/TabbedDialogScreen.h"
|
|
|
|
|
|
|
|
UI::LinearLayout *TabbedUIDialogScreenWithGameBackground::AddTab(const char *tag, const std::string &title, bool isSearch) {
|
|
|
|
using namespace UI;
|
|
|
|
ViewGroup *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
|
|
|
scroll->SetTag(tag);
|
|
|
|
|
|
|
|
LinearLayout *contents = new LinearLayoutList(ORIENT_VERTICAL);
|
|
|
|
contents->SetSpacing(0);
|
|
|
|
scroll->Add(contents);
|
|
|
|
tabHolder_->AddTab(title, scroll);
|
|
|
|
|
|
|
|
if (!isSearch) {
|
|
|
|
settingTabContents_.push_back(contents);
|
|
|
|
|
2023-12-20 09:35:02 +00:00
|
|
|
auto se = GetI18NCategory(I18NCat::SEARCH);
|
2023-06-16 11:44:35 +00:00
|
|
|
auto notice = contents->Add(new TextView(se->T("Filtering settings by '%1'"), new LinearLayoutParams(Margins(20, 5))));
|
|
|
|
notice->SetVisibility(V_GONE);
|
|
|
|
settingTabFilterNotices_.push_back(notice);
|
|
|
|
}
|
|
|
|
|
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabbedUIDialogScreenWithGameBackground::CreateViews() {
|
|
|
|
PreCreateViews();
|
|
|
|
|
|
|
|
bool vertical = UseVerticalLayout();
|
|
|
|
|
|
|
|
// Information in the top left.
|
|
|
|
// Back button to the bottom left.
|
|
|
|
// Scrolling action menu to the right.
|
|
|
|
using namespace UI;
|
|
|
|
|
|
|
|
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
|
|
|
|
|
|
|
|
if (vertical) {
|
2023-12-20 09:35:02 +00:00
|
|
|
auto di = GetI18NCategory(I18NCat::DIALOG);
|
2023-06-16 11:44:35 +00:00
|
|
|
LinearLayout *verticalLayout = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
|
|
|
|
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 200, new LinearLayoutParams(1.0f));
|
|
|
|
verticalLayout->Add(tabHolder_);
|
|
|
|
verticalLayout->Add(new Choice(di->T("Back"), "", false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0))))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
|
|
|
root_->Add(verticalLayout);
|
|
|
|
} else {
|
|
|
|
tabHolder_ = new TabHolder(ORIENT_VERTICAL, 200, new AnchorLayoutParams(10, 0, 10, 0, false));
|
|
|
|
root_->Add(tabHolder_);
|
|
|
|
AddStandardBack(root_);
|
|
|
|
}
|
2023-06-18 10:22:36 +00:00
|
|
|
tabHolder_->SetTag(tag()); // take the tag from the screen.
|
2023-06-16 11:44:35 +00:00
|
|
|
root_->SetDefaultFocusView(tabHolder_);
|
|
|
|
settingTabContents_.clear();
|
|
|
|
settingTabFilterNotices_.clear();
|
|
|
|
|
|
|
|
float leftSide = 40.0f;
|
|
|
|
if (!vertical) {
|
|
|
|
leftSide += 200.0f;
|
|
|
|
}
|
2023-07-08 08:45:22 +00:00
|
|
|
settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, g_display.dp_yres - 200.0f, new AnchorLayoutParams(
|
2023-06-16 11:44:35 +00:00
|
|
|
g_display.dp_xres - leftSide - 40.0f, WRAP_CONTENT,
|
|
|
|
leftSide, g_display.dp_yres - 80.0f - 40.0f, NONE, NONE));
|
|
|
|
root_->Add(settingInfo_);
|
|
|
|
|
|
|
|
// Show it again if we recreated the view
|
|
|
|
if (!oldSettingInfo_.empty()) {
|
|
|
|
settingInfo_->Show(oldSettingInfo_, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let the subclass create its tabs.
|
|
|
|
CreateTabs();
|
|
|
|
|
2023-06-21 22:24:36 +00:00
|
|
|
if (System_GetPropertyBool(SYSPROP_HAS_KEYBOARD) || System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) {
|
|
|
|
// Hide search if screen is too small.
|
|
|
|
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
|
|
|
if ((g_display.dp_xres < g_display.dp_yres || g_display.dp_yres >= 500) && (deviceType != DEVICE_TYPE_VR) && ShowSearchControls()) {
|
|
|
|
auto se = GetI18NCategory(I18NCat::SEARCH);
|
2023-12-20 09:35:02 +00:00
|
|
|
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
|
2023-06-21 22:24:36 +00:00
|
|
|
// Search
|
|
|
|
LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true);
|
|
|
|
|
|
|
|
searchSettings->Add(new ItemHeader(se->T("Find settings")));
|
2024-01-18 10:55:39 +00:00
|
|
|
searchSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([=](UI::EventParams &e) {
|
2023-09-30 09:21:22 +00:00
|
|
|
System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, StripSpaces(searchFilter_));
|
2023-06-21 22:24:36 +00:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
});
|
|
|
|
|
|
|
|
clearSearchChoice_ = searchSettings->Add(new Choice(se->T("Clear filter")));
|
|
|
|
clearSearchChoice_->OnClick.Add([=](UI::EventParams &e) {
|
2023-09-30 09:21:22 +00:00
|
|
|
System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, "");
|
2023-06-21 22:24:36 +00:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
});
|
|
|
|
|
|
|
|
noSearchResults_ = searchSettings->Add(new TextView(se->T("No settings matched '%1'"), new LinearLayoutParams(Margins(20, 5))));
|
|
|
|
|
|
|
|
ApplySearchFilter();
|
2023-06-16 11:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-30 09:21:22 +00:00
|
|
|
void TabbedUIDialogScreenWithGameBackground::sendMessage(UIMessage message, const char *value) {
|
2023-06-16 11:44:35 +00:00
|
|
|
UIDialogScreenWithGameBackground::sendMessage(message, value);
|
2023-09-30 09:21:22 +00:00
|
|
|
if (message == UIMessage::GAMESETTINGS_SEARCH) {
|
2023-06-16 11:44:35 +00:00
|
|
|
std::string filter = value ? value : "";
|
|
|
|
searchFilter_.resize(filter.size());
|
|
|
|
std::transform(filter.begin(), filter.end(), searchFilter_.begin(), tolower);
|
|
|
|
|
|
|
|
ApplySearchFilter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabbedUIDialogScreenWithGameBackground::RecreateViews() {
|
|
|
|
oldSettingInfo_ = settingInfo_ ? settingInfo_->GetText() : "N/A";
|
|
|
|
UIScreen::RecreateViews();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabbedUIDialogScreenWithGameBackground::ApplySearchFilter() {
|
|
|
|
auto se = GetI18NCategory(I18NCat::SEARCH);
|
|
|
|
|
|
|
|
bool matches = searchFilter_.empty();
|
|
|
|
for (int t = 0; t < (int)settingTabContents_.size(); ++t) {
|
|
|
|
auto tabContents = settingTabContents_[t];
|
|
|
|
bool tabMatches = searchFilter_.empty();
|
|
|
|
|
|
|
|
// Show an indicator that a filter is applied.
|
|
|
|
settingTabFilterNotices_[t]->SetVisibility(tabMatches ? UI::V_GONE : UI::V_VISIBLE);
|
2023-07-16 14:16:47 +00:00
|
|
|
settingTabFilterNotices_[t]->SetText(ApplySafeSubstitutions(se->T("Filtering settings by '%1'"), searchFilter_));
|
2023-06-16 11:44:35 +00:00
|
|
|
|
|
|
|
UI::View *lastHeading = nullptr;
|
|
|
|
for (int i = 1; i < tabContents->GetNumSubviews(); ++i) {
|
|
|
|
UI::View *v = tabContents->GetViewByIndex(i);
|
|
|
|
if (!v->CanBeFocused()) {
|
|
|
|
lastHeading = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string label = v->DescribeText();
|
|
|
|
std::transform(label.begin(), label.end(), label.begin(), tolower);
|
|
|
|
bool match = v->CanBeFocused() && label.find(searchFilter_) != label.npos;
|
|
|
|
tabMatches = tabMatches || match;
|
|
|
|
|
|
|
|
if (match && lastHeading)
|
|
|
|
lastHeading->SetVisibility(UI::V_VISIBLE);
|
|
|
|
v->SetVisibility(searchFilter_.empty() || match ? UI::V_VISIBLE : UI::V_GONE);
|
|
|
|
}
|
|
|
|
tabHolder_->EnableTab(t, tabMatches);
|
|
|
|
matches = matches || tabMatches;
|
|
|
|
}
|
|
|
|
|
2023-07-16 14:16:47 +00:00
|
|
|
noSearchResults_->SetText(ApplySafeSubstitutions(se->T("No settings matched '%1'"), searchFilter_));
|
2023-06-16 11:44:35 +00:00
|
|
|
noSearchResults_->SetVisibility(matches ? UI::V_GONE : UI::V_VISIBLE);
|
|
|
|
clearSearchChoice_->SetVisibility(searchFilter_.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
|
|
|
}
|