Merge pull request #22977 from hrydgard/touch-scroll-click-fixes

UI: Touch scrolling click fixes, UMD switch screen in portrait
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-11-07 11:40:47 +01:00
commit af763fffdf
15 files changed
+145 -81

No files matched your search

+21 -2
View File
@@ -20,6 +20,8 @@ TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds
}
// Mouse / 1-finger-touch control.
Pointer &p = pointers[touch.id];
const float dragThreshold = 5.0f / g_display.dpi_scale_y;
bool cancelUp = false;
if ((touch.flags & TouchInputFlags::DOWN) && bounds.Contains(touch.x, touch.y)) {
p.down = true;
p.downTime = time_now_d();
@@ -32,6 +34,20 @@ TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds
p.estimatedInertiaX = 0.0f;
p.estimatedInertiaY = 0.0f;
} else if (touch.flags & TouchInputFlags::UP) {
// The finger can move between the last MOVE and the UP (a quick flick may not have a MOVE at all),
// so a drag can first show up here. It's too late to scroll, but the press mustn't become a click.
if (p.down && !p.active) {
p.distanceX += fabsf(touch.x - p.lastX);
p.distanceY += fabsf(touch.y - p.lastY);
p.lastX = touch.x;
p.lastY = touch.y;
if ((gestureMask_ & GESTURE_DRAG_VERTICAL) && p.distanceY > p.distanceX && p.distanceY > dragThreshold) {
cancelUp = true;
}
if ((gestureMask_ & GESTURE_DRAG_HORIZONTAL) && p.distanceX > p.distanceY && p.distanceX > dragThreshold) {
cancelUp = true;
}
}
p.down = false;
} else {
p.distanceX += fabsf(touch.x - p.lastX);
@@ -46,8 +62,6 @@ TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds
p.lastY = touch.y;
}
const float dragThreshold = 5.0f / g_display.dpi_scale_y;
if ((gestureMask_ & GESTURE_DRAG_VERTICAL) && p.distanceY > p.distanceX) {
if (p.down) {
double timeDown = time_now_d() - p.downTime;
@@ -78,6 +92,11 @@ TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds
}
}
if (cancelUp) {
TouchInput inp2 = touch;
inp2.flags |= TouchInputFlags::CANCEL;
return inp2;
}
return touch;
}
+14 -7
View File
@@ -662,13 +662,13 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
LinearLayout *lin = vert->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::Margins(10, 10))));
Button *decrease = lin->Add(new Button("", ImageID("I_MINUS"), new LayoutParams(60.0f, 60.0f)));
decrease->OnClick.Handle(this, &SliderPopupScreen::OnDecrease);
decrease->SetRoundCorners();
Button *increase = lin->Add(new Button("", ImageID("I_PLUS"), new LayoutParams(60.0f, 60.0f)));
increase->OnClick.Handle(this, &SliderPopupScreen::OnIncrease);
increase->SetRoundCorners();
edit_ = new TextEdit("", Title(), "", new LinearLayoutParams(1.0f));
edit_->SetMaxLen(16);
edit_->SetTextColor(dc.GetTheme().itemStyle.fgColor);
edit_->SetTextAlign(FLAG_DYNAMIC_ASCII);
edit_->OnTextChange.Handle(this, &SliderPopupScreen::OnTextChange);
changing_ = true;
UpdateTextBox();
@@ -676,7 +676,7 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
lin->Add(edit_);
if (!units_.empty())
lin->Add(new TextView(units_));
lin->Add(new TextView(units_, new LinearLayoutParams(0.0f, Gravity::G_VCENTER)));
if (defaultValue_ != NO_DEFAULT_FLOAT) {
auto di = GetI18NCategory(I18NCat::DIALOG);
@@ -687,12 +687,13 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
UpdateTextBox();
changing_ = false;
});
reset->SetRoundCorners();
}
if (!negativeLabel_.empty())
vert->Add(new CheckBox(&disabled_, negativeLabel_));
lin->ApplyRoundCorners();
if (IsFocusMovementEnabled())
UI::SetFocusedView(slider_, FocusFlags::CAUSE_SCREEN_CHANGE);
}
@@ -708,8 +709,10 @@ void SliderFloatPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
vert->Add(slider_);
LinearLayout *lin = vert->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::Margins(10, 10))));
lin->Add(new Button("", ImageID("I_MINUS"), new LayoutParams(60.0f, 60.0f)))->OnClick.Handle(this, &SliderFloatPopupScreen::OnDecrease);
lin->Add(new Button("", ImageID("I_PLUS"), new LayoutParams(60.0f, 60.0f)))->OnClick.Handle(this, &SliderFloatPopupScreen::OnIncrease);
Button *decrease = lin->Add(new Button("", ImageID("I_MINUS"), new LayoutParams(60.0f, 60.0f)));
decrease->OnClick.Handle(this, &SliderFloatPopupScreen::OnDecrease);
Button *increase = lin->Add(new Button("", ImageID("I_PLUS"), new LayoutParams(60.0f, 60.0f)));
increase->OnClick.Handle(this, &SliderFloatPopupScreen::OnIncrease);
edit_ = new TextEdit("", Title(), "", new LinearLayoutParams(1.0f));
edit_->SetMaxLen(16);
@@ -720,18 +723,22 @@ void SliderFloatPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
UpdateTextBox();
changing_ = false;
lin->Add(edit_);
if (!units_.empty())
lin->Add(new TextView(units_))->SetTextColor(dc.GetTheme().itemStyle.fgColor);
if (defaultValue_ != NO_DEFAULT_FLOAT) {
auto di = GetI18NCategory(I18NCat::DIALOG);
lin->Add(new Button(di->T("Reset"), new LayoutParams(WRAP_CONTENT, 60.0f)))->OnClick.Add([=](UI::EventParams &) {
Button *reset = lin->Add(new Button(di->T("Reset"), new LayoutParams(WRAP_CONTENT, 60.0f)));
reset->OnClick.Add([=](UI::EventParams &) {
sliderValue_ = defaultValue_;
if (liveUpdate_) {
*value_ = defaultValue_;
}
});
reset->SetRoundCorners();
}
lin->ApplyRoundCorners();
// slider_ = parent->Add(new SliderFloat(&sliderValue_, minValue_, maxValue_, new LinearLayoutParams(UI::Margins(10, 5))));
if (IsFocusMovementEnabled())
+9
View File
@@ -167,6 +167,8 @@ bool ScrollView::Key(const KeyInput &input) {
const float friction = 0.92f;
const float stop_threshold = 0.1f;
// Scroll speed (per frame) above which a press only stops the list.
const float flingStopMinSpeed = 1.0f;
bool ScrollView::Touch(const TouchInput &input) {
if (input.flags & TouchInputFlags::MOUSE) {
@@ -180,7 +182,11 @@ bool ScrollView::Touch(const TouchInput &input) {
return ViewGroup::Touch(input);
}
bool stopsFling = false;
if ((input.flags & TouchInputFlags::DOWN) && scrollTouchId_ == -1 && bounds_.Contains(input.x, input.y)) {
// A press that stops a moving list only stops it, as in Android's lists, so it's kept from the children.
// The second check skips a list that is pushing against its end, which doesn't visibly move.
stopsFling = fabsf(inertia_) > flingStopMinSpeed && ClampedScrollPos(scrollPos_ - inertia_) != scrollPos_;
if (orientation_ == ORIENT_VERTICAL) {
Bob bob = ComputeBob();
float internalY = input.y - bounds_.y;
@@ -241,6 +247,9 @@ bool ScrollView::Touch(const TouchInput &input) {
scrollToTarget_ = false;
}
if (stopsFling) {
return true;
}
if (!(input.flags & TouchInputFlags::DOWN) || bounds_.Contains(input.x, input.y)) {
return ViewGroup::Touch(input2);
} else {
+1 -1
View File
@@ -458,7 +458,7 @@ static constexpr ConfigSetting generalSettings[] = {
ConfigSetting("RemoteISOSharedDir", SETTING(g_Config, sRemoteISOSharedDir), "", CfgFlag::DEFAULT),
ConfigSetting("RemoteISOShareType", SETTING(g_Config, iRemoteISOShareType), (int)RemoteISOShareType::RECENT, CfgFlag::DEFAULT),
ConfigSetting("AskForExitConfirmationAfterSeconds", SETTING(g_Config, iAskForExitConfirmationAfterSeconds), 300, CfgFlag::PER_GAME)
.Label(I18NCat::SYSTEM, "Ask for exit confirmation after seconds").Range(0, 1200).Units("s").ZeroLabel("Off"),
.Label(I18NCat::SYSTEM, "Ask for exit confirmation after seconds").Range(0, 1200).Units("seconds").ZeroLabel("Off"),
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
ConfigSetting("ScreenRotation", SETTING(g_Config, iScreenRotation), ROTATION_AUTO, CfgFlag::DEFAULT),
+4 -12
View File
@@ -23,14 +23,8 @@
#pragma once
#ifdef _MSC_VER
#define PACK // on MSVC we use #pragma pack() instead so let's kill this.
#pragma pack(push, 1)
#else
#define PACK __attribute__((packed))
#endif
typedef struct PSPParsedUri {
// This used to have pragma pack, but useless as all members are naturally aligned.
struct PSPParsedUri {
s32 noSlash;
s32 schemeAddr;
s32 userInfoUserNameAddr;
@@ -41,10 +35,8 @@ typedef struct PSPParsedUri {
s32 fragmentAddr;
u16 port;
u8 unknown[10]; // padding might be included here?
} PACK PSPParsedUri;
};
#ifdef _MSC_VER
#pragma pack(pop)
#endif
static_assert(sizeof(PSPParsedUri) == 44, "PSPParsedUri size mismatch");
void Register_sceParseUri();
+1 -1
View File
@@ -209,7 +209,7 @@ void FirmwareScreen::CreateSettingsViews(UI::ViewGroup *parent) {
Choice *moreInfo = groups->Add(new ChoiceGroup())->Add(new Choice(di->T("More info")));
moreInfo->OnClick.Add([](UI::EventParams &) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/getting-started/how-to-run-the-vsh/");
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/getting-started/how-to-run-the-xmb/");
});
moreInfo->SetIconRight(ImageID("I_LINK_OUT"));
+40 -3
View File
@@ -38,6 +38,7 @@
#include "Core/HLE/sceCtrl.h"
#include "Core/ELF/PBPReader.h"
#include "Core/FileLoaders/PS1EbootFileLoader.h"
#include "Core/Loaders.h"
#include "Core/MemMap.h"
#include "UI/GameBrowser.h"
@@ -277,11 +278,42 @@ void GameBrowser::PinToggleClick(UI::EventParams &e) {
refreshPending_ = true;
}
// Whether UmdMount takes it: a PSP disc image (also a UMD video, or a PSN game's ISO in an EBOOT.PBP),
// or a disc's files in a directory.
static bool IsUmdPath(const Path &path, bool isDirectory) {
if (!isDirectory) {
const std::string ext = path.GetFileExtension();
// Trusted by name, since opening every image would make big folders slow to list.
if (ext == ".iso" || ext == ".cso") {
return true;
}
// A CHD can hold a PS1 disc, and a PBP can be homebrew or a PS1 game.
if (ext != ".chd" && ext != ".pbp") {
return false;
}
}
std::unique_ptr<FileLoader> loader(ConstructFileLoader(path));
std::string error;
switch (Identify_File(loader.get(), &error)) {
case IdentifiedFileType::PSP_ISO:
case IdentifiedFileType::PSP_ISO_NP:
case IdentifiedFileType::PSP_DISC_DIRECTORY:
case IdentifiedFileType::PSP_UMD_VIDEO_ISO:
return true;
default:
return false;
}
}
bool GameBrowser::HasSpecialFiles(std::vector<Path> &filenames) {
if (path_.GetPath().ToString() == "!RECENT") {
filenames.clear();
for (auto &str : g_recentFiles.GetRecentFiles()) {
filenames.emplace_back(str);
Path path(str);
if ((browseFlags_ & BrowseFlags::UMDS_ONLY) && !IsUmdPath(path, File::IsDirectory(path))) {
continue;
}
filenames.push_back(path);
}
return true;
}
@@ -524,8 +556,9 @@ void GameBrowser::Refresh() {
gameButtons.push_back(new GameButton(GameButtonType::Game, filenames[i], lastViewMode_, new UI::LinearLayoutParams(gridStyle ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT)));
}
} else if (!listingPending_) {
const bool umdsOnly = browseFlags_ & BrowseFlags::UMDS_ONLY;
std::vector<File::FileInfo> fileInfo;
path_.GetListing(fileInfo, "iso:cso:chd:pbp:elf:prx:ppdmp:cue:ccd:mds:bin:img:");
path_.GetListing(fileInfo, umdsOnly ? "iso:cso:chd:pbp:" : "iso:cso:chd:pbp:elf:prx:ppdmp:cue:ccd:mds:bin:img:");
// PS1 discs: a .bin or .img shows up as its cue sheet or .ccd, when it has one.
RemoveDescribedDiscImages(&fileInfo);
// Drives and servers aren't games, and probing a server that's gone away can take seconds.
@@ -543,6 +576,10 @@ void GameBrowser::Refresh() {
else if (!isGame && File::Exists(path_.GetPath() / fileInfo[i].name / "PARAM.SFO"))
isSaveData = true;
if (umdsOnly && (isSaveData || (isGame && !IsUmdPath(fileInfo[i].fullName, fileInfo[i].isDirectory)))) {
continue;
}
if (!isGame && !isSaveData) {
if (browseFlags_ & BrowseFlags::NAVIGATE) {
dirButtons.push_back(new GameButton(GameButtonType::Dir, fileInfo[i].fullName, lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)));
@@ -558,7 +595,7 @@ void GameBrowser::Refresh() {
// Put RAR/ZIP files at the end to get them out of the way. Game update packages go here
// too - they're not something to boot, they're something to install.
// We do support unpacking some of them automatically.
if (browseFlags_ & BrowseFlags::ARCHIVES) {
if ((browseFlags_ & BrowseFlags::ARCHIVES) && !umdsOnly) {
fileInfo.clear();
path_.GetListing(fileInfo, "zip:rar:r00:r01:7z:pkg:");
if (!fileInfo.empty()) {
+1
View File
@@ -28,6 +28,7 @@ enum class BrowseFlags {
PIN = 8,
HOMEBREW_STORE = 16,
UPLOAD_BUTTON = 32,
UMDS_ONLY = 64, // Only what can go in the UMD drive (see UmdMount).
STANDARD = 1 | 2 | 4 | 8 | 32,
};
ENUM_CLASS_BITOPS(BrowseFlags);
+28 -32
View File
@@ -939,51 +939,63 @@ void MainScreen::dialogFinished(const Screen *dialog, DialogResult result) {
}
}
void UmdReplaceScreen::CreateViews() {
std::string_view UmdReplaceScreen::GetTitle() const {
auto pa = GetI18NCategory(I18NCat::PAUSE);
return insert_ ? pa->T("Insert UMD") : pa->T("Switch UMD");
}
void UmdReplaceScreen::CreateContentViews(UI::ViewGroup *parent) {
using namespace UI;
Margins actionMenuMargins(0, 100, 15, 0);
auto mm = GetI18NCategory(I18NCat::MAINMENU);
auto di = GetI18NCategory(I18NCat::DIALOG);
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, TabHolderFlags::Default, nullptr, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0));
leftColumn->SetTag("UmdReplace");
leftColumn->SetClip(true);
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(270, FILL_PARENT, actionMenuMargins));
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
rightColumnItems->SetSpacing(0.0f);
rightColumn->Add(rightColumnItems);
TabHolder *tabs = new TabHolder(ORIENT_HORIZONTAL, 64, TabHolderFlags::Default, nullptr, nullptr, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
tabs->SetTag("UmdReplace");
tabs->SetClip(true);
parent->Add(tabs);
if (g_Config.iMaxRecent > 0) {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("UmdReplaceRecentGames");
GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
Path("!RECENT"), BrowseFlags::NONE, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "",
Path("!RECENT"), BrowseFlags::UMDS_ONLY, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollRecentGames->Add(tabRecentGames);
leftColumn->AddTab(mm->T("Recent"), ImageID::invalid(), scrollRecentGames);
tabs->AddTab(mm->T("Recent"), ImageID::invalid(), scrollRecentGames);
tabRecentGames->OnChoice.Handle(this, &UmdReplaceScreen::OnGameSelected);
tabRecentGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected);
}
ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollAllGames->SetTag("UmdReplaceAllGames");
GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, portrait, &g_Config.iGameBrowserView2, screenManager(),
GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD | BrowseFlags::UMDS_ONLY, portrait, &g_Config.iGameBrowserView2, screenManager(),
mm->T("How to get games"), "https://www.ppsspp.org/getgames.html",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollAllGames->Add(tabAllGames);
leftColumn->AddTab(mm->T("Games"), ImageID::invalid(), scrollAllGames);
tabs->AddTab(mm->T("Games"), ImageID::invalid(), scrollAllGames);
tabAllGames->OnChoice.Handle(this, &UmdReplaceScreen::OnGameSelected);
tabAllGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected);
if (g_recentFiles.HasAny()) {
tabs->SetCurrentTab(0, true);
} else if (g_Config.iMaxRecent > 0) {
tabs->SetCurrentTab(1, true);
}
}
void UmdReplaceScreen::CreateSettingsViews(UI::ViewGroup *parent) {
using namespace UI;
auto mm = GetI18NCategory(I18NCat::MAINMENU);
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Add([&](UI::EventParams &e) {
ChoiceGroupList *settings = parent->Add(new ChoiceGroupList());
ChoiceGroup *choices = settings->Add(new ChoiceGroup());
choices->Add(new Choice(mm->T("Load", "Load..."), ImageID("I_FOLDER_OPEN")))->OnClick.Add([this](UI::EventParams &e) {
auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(GetRequesterToken(), mm->T("Load"), BrowseFileType::BOOTABLE, [this](std::string_view value, int) {
UseDisc(Path(value));
@@ -991,22 +1003,6 @@ void UmdReplaceScreen::CreateViews() {
});
});
}
rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnCancel);
rightColumnItems->Add(new Spacer());
rightColumnItems->Add(new Choice(mm->T("Game Settings")))->OnClick.Add([this](UI::EventParams &e) {
screenManager()->push(new GameSettingsScreen(Path()));
});
if (g_recentFiles.HasAny()) {
leftColumn->SetCurrentTab(0, true);
} else if (g_Config.iMaxRecent > 0) {
leftColumn->SetCurrentTab(1, true);
}
root_ = new LinearLayout(ORIENT_HORIZONTAL);
root_->Add(leftColumn);
root_->Add(rightColumn);
}
void UmdReplaceScreen::update() {
+7 -3
View File
@@ -26,6 +26,7 @@
#include "Common/UI/TabHolder.h"
#include "Common/UI/PopupScreens.h"
#include "UI/BaseScreens.h"
#include "UI/SimpleDialogScreen.h"
#include "Common/File/PathBrowser.h"
#include "UI/GameBrowser.h"
@@ -103,14 +104,17 @@ private:
void InstantHighlight(const Path &path);
};
class UmdReplaceScreen : public UIBaseDialogScreen {
class UmdReplaceScreen : public UITwoPaneBaseDialogScreen {
public:
// insert: put a disc into the empty drive (the VSH) rather than swap the one a game is running from.
explicit UmdReplaceScreen(bool insert = false) : insert_(insert) {}
explicit UmdReplaceScreen(bool insert = false)
: UITwoPaneBaseDialogScreen(Path(), TwoPaneFlags::SettingsToTheRight | TwoPaneFlags::NoTopbarInLandscape), insert_(insert) {}
const char *tag() const override { return "UmdReplace"; }
protected:
void CreateViews() override;
std::string_view GetTitle() const override;
void CreateSettingsViews(UI::ViewGroup *parent) override;
void CreateContentViews(UI::ViewGroup *parent) override;
void update() override;
private:
+2 -1
View File
@@ -250,7 +250,7 @@ void GameImageView::Draw(UIContext &dc) {
dc.RebindTexture();
}
void AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool text) {
UI::View *AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool text) {
using namespace UI;
static const char *screenRotation[] = { "Auto", "Landscape", "Portrait", "Landscape Reversed", "N/A", "Landscape Auto"};
static const std::map<int, ImageID> screenRotationIcons{
@@ -277,6 +277,7 @@ void AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool
INFO_LOG(Log::System, "New display rotation: %d", g_Config.iScreenRotation);
System_Notify(SystemNotification::ROTATE_UPDATED);
});
return rot;
}
void GameInfoBGView::Draw(UIContext &dc) {
+1 -1
View File
@@ -105,7 +105,7 @@ private:
UI::View *setting_;
};
void AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool text);
UI::View *AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool text);
class SearchBar : public UI::InertView {
public:
+2 -3
View File
@@ -834,7 +834,6 @@ void GamePauseScreen::CreateViews() {
g_Config.bRunBehindPauseMenu = !g_Config.bRunBehindPauseMenu;
playButton_->SetIconLeft(g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE_LINE") : ImageID("I_PLAY_LINE"));
});
playButton_->SetRoundCorners();
bool mustRunBehind = MustRunBehind();
playButton_->SetEnabled(!mustRunBehind);
@@ -843,7 +842,6 @@ void GamePauseScreen::CreateViews() {
infoButton->OnClick.Add([this](UI::EventParams &e) {
screenManager()->push(new GameScreen(gamePath_, true));
});
infoButton->SetRoundCorners();
if (System_GetPropertyBool(SYSPROP_CAN_RESTRICT_ORIENTATION)) {
AddRotationPicker(screenManager(), middleColumn, false);
@@ -854,8 +852,9 @@ void GamePauseScreen::CreateViews() {
menuButton->OnClick.Add([this, menuButton, portrait](UI::EventParams &e) {
ShowContextMenu(menuButton, portrait);
});
menuButton->SetRoundCorners();
}
middleColumn->ApplyRoundCorners();
} else {
playButton_ = nullptr;
}
+2 -2
View File
@@ -195,9 +195,9 @@ public class NativeApp {
case MotionEvent.ACTION_CANCEL:
// The whole gesture is over (the system took it, for example), so every pointer in the
// event is, not just the one at the action index. Otherwise the rest stay held down
// on the native side. Handle like ACTION_UP for now.
// on the native side. UP | CANCEL, so the UI lets go without clicking.
Log.i(TAG, "ACTION_CANCEL");
code = 4;
code = 4 | 8;
break;
case MotionEvent.ACTION_MOVE: {
code = 1;
+12 -13
View File
@@ -212,6 +212,18 @@
"status_xml": "",
"icon": "https://raw.githubusercontent.com/MainPiyushHoon/Alpha-Community-Webpage/refs/heads/main/src/images/ALPHA.webp"
},
{
"name": "SWAENET",
"host": "132.226.189.224",
"discord": "https://discord.gg/CgZxfHA8ZC",
"web": "https://132.226.189.224/",
"location": "Mumbai, India",
"location-emoji": "🇮🇳",
"description": "SWAENET PPSSPP Relay – Mumbai, India – part of the SWAEYERS community, offering low‑latency, reliable gaming connectivity.",
"data_mode": "AemuPostoffice",
"status_data_json": "https://132.226.189.224/data.json",
"icon": "https://132.226.189.224/assets/favicon.svg"
},
{
"name": "aemu_postoffice test server",
"host": "185.183.157.234",
@@ -228,24 +240,11 @@
"name": "Andexplaystream",
"host": "psp.andexplaystream.online",
"discord": "",
"web": "",
"location": "Jakarta, Indonesia",
"location-emoji": "🇮🇩",
"description": "For players looking to play any games",
"data_mode": "AemuPostoffice",
"status_data_json": "http://psp.andexplaystream.online/data.json"
},
{
"name": "SWAENET",
"host": "132.226.189.224",
"discord": "https://discord.gg/CgZxfHA8ZC",
"web": "http://132.226.189.224:8888/",
"location": "Mumbai,India",
"location-emoji": "🇮🇳",
"description": "Indian adhoc relay from SWAEYERS community",
"data_mode": "AemuPostoffice",
"status_data_json": "http://132.226.189.224:8888/data.json",
"icon": "http://132.226.189.224:8888/assets/favicon.svg"
}
]
}