mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
1304d04161
It seems to be possible for a user to back out of a screen before receiving the "dialog completed" callback on Android, in which case things pointed to by the callback might be gone. In this case, it's better to simply not call the callback, rather than crashing. This is accomplished by assigning "Tokens" to screens that cause requests, and in ~Screen, invalidate any pending requests belonging to that token.
157 lines
5.9 KiB
C++
157 lines
5.9 KiB
C++
#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);
|
|
|
|
auto se = GetI18NCategory(I18NCat::SEARCH);
|
|
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) {
|
|
auto di = GetI18NCategory(I18NCat::DIALOG);
|
|
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_);
|
|
}
|
|
tabHolder_->SetTag(tag()); // take the tag from the screen.
|
|
root_->SetDefaultFocusView(tabHolder_);
|
|
settingTabContents_.clear();
|
|
settingTabFilterNotices_.clear();
|
|
|
|
float leftSide = 40.0f;
|
|
if (!vertical) {
|
|
leftSide += 200.0f;
|
|
}
|
|
settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, g_display.dp_yres - 200.0f, new AnchorLayoutParams(
|
|
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();
|
|
|
|
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);
|
|
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
|
|
// Search
|
|
LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true);
|
|
|
|
searchSettings->Add(new ItemHeader(se->T("Find settings")));
|
|
searchSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([=](UI::EventParams &e) {
|
|
System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, StripSpaces(searchFilter_));
|
|
return UI::EVENT_DONE;
|
|
});
|
|
|
|
clearSearchChoice_ = searchSettings->Add(new Choice(se->T("Clear filter")));
|
|
clearSearchChoice_->OnClick.Add([=](UI::EventParams &e) {
|
|
System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, "");
|
|
return UI::EVENT_DONE;
|
|
});
|
|
|
|
noSearchResults_ = searchSettings->Add(new TextView(se->T("No settings matched '%1'"), new LinearLayoutParams(Margins(20, 5))));
|
|
|
|
ApplySearchFilter();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabbedUIDialogScreenWithGameBackground::sendMessage(UIMessage message, const char *value) {
|
|
UIDialogScreenWithGameBackground::sendMessage(message, value);
|
|
if (message == UIMessage::GAMESETTINGS_SEARCH) {
|
|
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);
|
|
settingTabFilterNotices_[t]->SetText(ApplySafeSubstitutions(se->T("Filtering settings by '%1'"), searchFilter_));
|
|
|
|
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;
|
|
}
|
|
|
|
noSearchResults_->SetText(ApplySafeSubstitutions(se->T("No settings matched '%1'"), searchFilter_));
|
|
noSearchResults_->SetVisibility(matches ? UI::V_GONE : UI::V_VISIBLE);
|
|
clearSearchChoice_->SetVisibility(searchFilter_.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
|
}
|