diff --git a/Common/Input/GestureDetector.cpp b/Common/Input/GestureDetector.cpp index bf33013c21..a76ffa6ec4 100644 --- a/Common/Input/GestureDetector.cpp +++ b/Common/Input/GestureDetector.cpp @@ -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; } diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 4867fcc616..4a27d80fe0 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -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()) diff --git a/Common/UI/ScrollView.cpp b/Common/UI/ScrollView.cpp index 8eaa09d6c2..e391b38a74 100644 --- a/Common/UI/ScrollView.cpp +++ b/Common/UI/ScrollView.cpp @@ -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 { diff --git a/Core/Config.cpp b/Core/Config.cpp index 71759454f1..a56536f6cb 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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), diff --git a/Core/HLE/sceParseUri.h b/Core/HLE/sceParseUri.h index 5d7b677b2c..1aaabf6b5c 100644 --- a/Core/HLE/sceParseUri.h +++ b/Core/HLE/sceParseUri.h @@ -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(); diff --git a/UI/FirmwareScreen.cpp b/UI/FirmwareScreen.cpp index 6890b6a34a..3aa16c5c04 100644 --- a/UI/FirmwareScreen.cpp +++ b/UI/FirmwareScreen.cpp @@ -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")); diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index d752af6314..b40a08612d 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -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 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 &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 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()) { diff --git a/UI/GameBrowser.h b/UI/GameBrowser.h index 0f429ac243..49c4f87229 100644 --- a/UI/GameBrowser.h +++ b/UI/GameBrowser.h @@ -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); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index c6f9ab964f..169521831d 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -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(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() { diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 7a61a2e250..df0dc11f61 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -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: diff --git a/UI/MiscViews.cpp b/UI/MiscViews.cpp index a95bc6fa30..e91b4a2983 100644 --- a/UI/MiscViews.cpp +++ b/UI/MiscViews.cpp @@ -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 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) { diff --git a/UI/MiscViews.h b/UI/MiscViews.h index e0b20fa2b3..d001fc346f 100644 --- a/UI/MiscViews.h +++ b/UI/MiscViews.h @@ -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: diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 6354d3c78c..3dd72888a7 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -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; } diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java index 8484ee5c35..dfe419ca22 100644 --- a/android/src/org/ppsspp/ppsspp/NativeApp.java +++ b/android/src/org/ppsspp/ppsspp/NativeApp.java @@ -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; diff --git a/assets/adhoc-servers.json b/assets/adhoc-servers.json index f6ddbcc8d5..3deb6e16b1 100644 --- a/assets/adhoc-servers.json +++ b/assets/adhoc-servers.json @@ -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" } ] }