mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 09:39:33 +01:00
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:
15 files changed
+145
-81
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
@@ -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
@@ -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()) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user