From 0066599f9a122ee082991e7145514fa62c84c322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 10:24:32 +0200 Subject: [PATCH 1/8] Game browser: Add an XMB-style large list mode - Fixes #22202 A third view mode next to grid and list: a list with full size icons, scaled by the grid icon size setting. Like the XMB, the selected (or hovered) game plays its ICON1.PMF in place of the icon. The per-tab grid bools become GameBrowserView1-4 ints. The old GridView keys are still read, to pick the default, but no longer saved. The PMF decoding moved out of GameScreen's PMFView into a shared PMFVideoTexture. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/Config.cpp | 22 +++++- Core/Config.h | 7 +- Core/ConfigValues.h | 6 ++ UI/GameBrowser.cpp | 153 +++++++++++++++++++++++++++++------- UI/GameBrowser.h | 8 +- UI/GameScreen.cpp | 71 ++--------------- UI/MainScreen.cpp | 24 +++--- UI/MainScreen.h | 2 +- UI/MiscViews.cpp | 52 ++++++++++++ UI/MiscViews.h | 29 +++++++ UI/RemoteISOScreen.cpp | 2 +- UI/UIAtlas.cpp | 1 + assets/ui_images/images.svg | 19 ++++- 13 files changed, 279 insertions(+), 117 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index fde77e6207..17dd44d34a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -195,6 +195,15 @@ static bool DefaultEnableStateUndo() { return true; } +static int GameBrowserViewFromGridView(bool gridView) { + return (int)(gridView ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST); +} + +static int DefaultGameBrowserView1() { return GameBrowserViewFromGridView(g_Config.bGridView1); } +static int DefaultGameBrowserView2() { return GameBrowserViewFromGridView(g_Config.bGridView2); } +static int DefaultGameBrowserView3() { return GameBrowserViewFromGridView(g_Config.bGridView3); } +static int DefaultGameBrowserView4() { return GameBrowserViewFromGridView(g_Config.bGridView4); } + static float DefaultGameGridScale() { #if PPSSPP_PLATFORM(IOS) return 1.25f; @@ -283,10 +292,15 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("ShowRegionOnGameIcon", SETTING(g_Config, bShowRegionOnGameIcon), false, CfgFlag::DEFAULT), ConfigSetting("ShowIDOnGameIcon", SETTING(g_Config, bShowIDOnGameIcon), false, CfgFlag::DEFAULT), ConfigSetting("GameGridScale", SETTING(g_Config, fGameGridScale), &DefaultGameGridScale, CfgFlag::DEFAULT), - ConfigSetting("GridView1", SETTING(g_Config, bGridView1), true, CfgFlag::DEFAULT), - ConfigSetting("GridView2", SETTING(g_Config, bGridView2), true, CfgFlag::DEFAULT), - ConfigSetting("GridView3", SETTING(g_Config, bGridView3), false, CfgFlag::DEFAULT), - ConfigSetting("GridView4", SETTING(g_Config, bGridView4), false, CfgFlag::DEFAULT), + ConfigSetting("GridView1", SETTING(g_Config, bGridView1), true, CfgFlag::DONT_SAVE), + ConfigSetting("GridView2", SETTING(g_Config, bGridView2), true, CfgFlag::DONT_SAVE), + ConfigSetting("GridView3", SETTING(g_Config, bGridView3), false, CfgFlag::DONT_SAVE), + ConfigSetting("GridView4", SETTING(g_Config, bGridView4), false, CfgFlag::DONT_SAVE), + // These must come after GridView*, which their defaults are taken from. + ConfigSetting("GameBrowserView1", SETTING(g_Config, iGameBrowserView1), &DefaultGameBrowserView1, CfgFlag::DEFAULT), + ConfigSetting("GameBrowserView2", SETTING(g_Config, iGameBrowserView2), &DefaultGameBrowserView2, CfgFlag::DEFAULT), + ConfigSetting("GameBrowserView3", SETTING(g_Config, iGameBrowserView3), &DefaultGameBrowserView3, CfgFlag::DEFAULT), + ConfigSetting("GameBrowserView4", SETTING(g_Config, iGameBrowserView4), &DefaultGameBrowserView4, CfgFlag::DEFAULT), ConfigSetting("RightAnalogUp", SETTING(g_Config, iRightAnalogUp), 0, CfgFlag::PER_GAME), ConfigSetting("RightAnalogDown", SETTING(g_Config, iRightAnalogDown), 0, CfgFlag::PER_GAME), ConfigSetting("RightAnalogLeft", SETTING(g_Config, iRightAnalogLeft), 0, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 6fa8be43ea..d472373c15 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -468,7 +468,12 @@ public: int iTiltInputType; bool bTiltInputEnabled; - // The four tabs (including Remote last) + // The four tabs (including Remote last). Values from GameBrowserViewMode. + int iGameBrowserView1; + int iGameBrowserView2; + int iGameBrowserView3; + int iGameBrowserView4; + // Only read, to migrate to iGameBrowserView*. bool bGridView1; bool bGridView2; bool bGridView3; diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 3fd223cf02..9a5428c361 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -302,3 +302,9 @@ enum class RemoteISOShareType : int { RECENT, LOCAL_FOLDER, }; + +enum class GameBrowserViewMode : int { + GRID = 0, + LIST = 1, + LARGE_LIST = 2, // XMB-style, with full size icons and the ICON1.PMF video. +}; diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index bc394e0028..e5df693610 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -38,6 +38,7 @@ #include "Core/Util/RecentFiles.h" #include "Core/HLE/sceCtrl.h" #include "Core/ELF/PBPReader.h" +#include "Core/Util/VideoPlayer.h" #include "UI/GameBrowser.h" #include "UI/RemoteISOScreen.h" @@ -49,7 +50,21 @@ #include "Common/Data/Text/I18n.h" #include "Core/Util/DarwinFileSystemServices.h" // For the browser -static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text, const Bounds &bounds, bool gridStyle, const UI::Style &style) { +// Icon dimensions in the large list, and its padding around the icon. +static constexpr float LARGE_LIST_ICON_W = 144.0f; +static constexpr float LARGE_LIST_ICON_H = 80.0f; +static constexpr float LARGE_LIST_PAD = 6.0f; + +// Where the text starts in the list modes. +static float ListTextX(GameBrowserViewMode viewMode) { + if (viewMode == GameBrowserViewMode::LARGE_LIST) { + return LARGE_LIST_PAD + LARGE_LIST_ICON_W * g_Config.fGameGridScale + 20.0f; + } + return 150.0f; +} + +static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text, const Bounds &bounds, GameBrowserViewMode viewMode, const UI::Style &style) { + const bool gridStyle = viewMode == GameBrowserViewMode::GRID; float tw, th; dc.MeasureText(dc.GetFontStyle(), gridStyle ? g_Config.fGameGridScale : 1.0, gridStyle ? g_Config.fGameGridScale : 1.0, text, &tw, &th, 0); @@ -82,15 +97,21 @@ static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text dc.SetFontStyle(dc.GetTheme().uiFont); dc.PopScissor(); } else { - dc.Draw()->DrawImage(image, bounds.x + 72, bounds.centerY(), 0.88f * (gridStyle ? g_Config.fGameGridScale : 1.0), style.fgColor, ALIGN_CENTER); + const float textX = ListTextX(viewMode); + if (viewMode == GameBrowserViewMode::LARGE_LIST) { + const float scale = g_Config.fGameGridScale; + dc.Draw()->DrawImage(image, bounds.x + LARGE_LIST_PAD + LARGE_LIST_ICON_W * 0.5f * scale, bounds.centerY(), 0.88f * scale, style.fgColor, ALIGN_CENTER); + } else { + dc.Draw()->DrawImage(image, bounds.x + 72, bounds.centerY(), 0.88f * (gridStyle ? g_Config.fGameGridScale : 1.0), style.fgColor, ALIGN_CENTER); + } - float tx = 150; - int availableWidth = bounds.w - 150; + float tx = textX; + int availableWidth = bounds.w - textX; float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; if (availableWidth < tw) { tx -= (1.0f + sin(time_now_d() * 1.5f)) * sineWidth; Bounds tb = bounds; - tb.x = bounds.x + 150; + tb.x = bounds.x + textX; tb.w = availableWidth; dc.PushScissor(tb); } @@ -103,8 +124,8 @@ static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text class GameButton : public UI::Clickable { public: - GameButton(const Path &gamePath, bool gridStyle, UI::LayoutParams *layoutParams = nullptr) - : UI::Clickable(layoutParams), gridStyle_(gridStyle), gamePath_(gamePath) {} + GameButton(const Path &gamePath, GameBrowserViewMode viewMode, UI::LayoutParams *layoutParams = nullptr) + : UI::Clickable(layoutParams), viewMode_(viewMode), gridStyle_(viewMode == GameBrowserViewMode::GRID), gamePath_(gamePath) {} void Draw(UIContext &dc) override; std::string DescribeText() const override; @@ -122,6 +143,9 @@ public: if (gridStyle_) { w = 144 * g_Config.fGameGridScale; h = 80 * g_Config.fGameGridScale; + } else if (viewMode_ == GameBrowserViewMode::LARGE_LIST) { + w = 500; + h = LARGE_LIST_ICON_H * g_Config.fGameGridScale + LARGE_LIST_PAD * 2; } else { w = 500; h = 50; @@ -188,6 +212,12 @@ public: TriggerOnHighlight(focusFlags); } + void DeviceLost() override { + if (video_) { + video_->DeviceLost(); + } + } + UI::Event OnHoldClick; UI::Event OnHighlight; @@ -208,10 +238,17 @@ private: OnHighlight.Trigger(e); } + void UpdateVideo(const std::shared_ptr &ginfo, bool wantVideo); + + GameBrowserViewMode viewMode_; bool gridStyle_; Path gamePath_; std::string title_; + // The ICON1.PMF video, played in place of the icon in the large list, like the XMB does. + std::unique_ptr video_; + Instant videoStart_; + double holdStart_ = 0.0; bool holdEnabled_ = true; bool showInfoPressed_ = false; @@ -219,8 +256,36 @@ private: bool hovering_ = false; }; +void GameButton::UpdateVideo(const std::shared_ptr &ginfo, bool wantVideo) { + if (!wantVideo) { + video_.reset(); + return; + } + if (video_ || !ginfo->Ready(GameInfoFlags::ICON1_PMF)) { + return; + } + std::string data; + { + std::lock_guard guard(ginfo->lock); + data = ginfo->icon1pmf; + } + if (!data.empty()) { + video_ = std::make_unique(std::move(data)); + videoStart_ = Instant::Now(); + } +} + void GameButton::Draw(UIContext &dc) { - std::shared_ptr ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON); + const bool largeList = viewMode_ == GameBrowserViewMode::LARGE_LIST; + // Like the XMB, only the selected game plays its video. The mouse can select one too, by hovering. + const bool wantVideo = largeList && (HasFocus() || hovering_) && pmf_player_available(); + + GameInfoFlags infoFlags = GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON; + if (wantVideo) { + infoFlags |= GameInfoFlags::ICON1_PMF; + } + std::shared_ptr ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath_, infoFlags); + UpdateVideo(ginfo, wantVideo); Draw::Texture *texture = nullptr; u32 color = 0, shadowColor = 0; using namespace UI; @@ -293,6 +358,13 @@ void GameButton::Draw(UIContext &dc) { int y = bounds_.y; int w = gridStyle_ ? bounds_.w : 144; int h = bounds_.h; + if (largeList) { + x += LARGE_LIST_PAD; + y += LARGE_LIST_PAD; + w = LARGE_LIST_ICON_W * g_Config.fGameGridScale; + h = LARGE_LIST_ICON_H * g_Config.fGameGridScale; + } + const float textX = ListTextX(viewMode_); if (!gridStyle_ || !texture) { if (HasFocus()) @@ -306,6 +378,13 @@ void GameButton::Draw(UIContext &dc) { dc.Draw()->Flush(); } + if (texture && video_) { + Draw::Texture *frame = video_->Update(dc.GetDrawContext(), videoStart_.ElapsedSeconds()); + if (frame) { + texture = frame; + } + } + if (texture) { color = whiteAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2)); shadowColor = blackAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2)); @@ -325,7 +404,7 @@ void GameButton::Draw(UIContext &dc) { // Render button int dropsize = 10; if (texture) { - if (!gridStyle_) { + if (!gridStyle_ && !largeList) { x += 4; } if (txOffset) { @@ -371,7 +450,7 @@ void GameButton::Draw(UIContext &dc) { if (down_) style = dc.GetTheme().itemDownStyle; if (!IsEnabled()) style = dc.GetTheme().itemDisabledStyle; - DrawIconWithText(dc, imageIcon, ginfo->GetTitle(), bounds_, gridStyle_, style); + DrawIconWithText(dc, imageIcon, ginfo->GetTitle(), bounds_, viewMode_, style); if (overlayColor) { dc.FillRect(Drawable(overlayColor), overlayBounds); @@ -397,22 +476,22 @@ void GameButton::Draw(UIContext &dc) { dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_, &tw, &th, 0); - int availableWidth = bounds_.w - 150; + int availableWidth = bounds_.w - textX; if (g_Config.bShowIDOnGameIcon) { float vw, vh; dc.MeasureText(dc.GetFontStyle(), 0.7f, 0.7f, ginfo->id_version, &vw, &vh, 0); availableWidth -= vw + 20; dc.SetFontScale(0.7f, 0.7f); - dc.DrawText(ginfo->id_version, bounds_.x + availableWidth + 160, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(ginfo->id_version, bounds_.x + availableWidth + textX + 10, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); } float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; - float tx = 150; + float tx = textX; if (availableWidth < tw) { tx -= (1.0f + sin(time_now_d() * 1.5f)) * sineWidth; Bounds tb = bounds_; - tb.x = bounds_.x + 150; + tb.x = bounds_.x + textX; tb.w = availableWidth; dc.PushScissor(tb); } @@ -438,6 +517,8 @@ void GameButton::Draw(UIContext &dc) { if (gearImage) { if (gridStyle_) { dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x, y + h - gearImage->h * g_Config.fGameGridScale, g_Config.fGameGridScale); + } else if (largeList) { + dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + LARGE_LIST_PAD, y + h - gearImage->h * g_Config.fGameGridScale, g_Config.fGameGridScale); } else { dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + 4, y, 1.0f); } @@ -459,6 +540,9 @@ void GameButton::Draw(UIContext &dc) { if (gridStyle_) { dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + bounds_.w - (image->w + 5) * g_Config.fGameGridScale, y + h - (image->h + 5) * g_Config.fGameGridScale, g_Config.fGameGridScale); + } else if (largeList) { + dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + LARGE_LIST_PAD + (LARGE_LIST_ICON_W - image->w - 5) * g_Config.fGameGridScale, + y + h - (image->h + 5) * g_Config.fGameGridScale, g_Config.fGameGridScale); } else { dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + 4, y + h - image->h - 5, 1.0f); } @@ -530,11 +614,11 @@ void DirButton::Draw(UIContext &dc) { if (!IsEnabled()) style = dc.GetTheme().itemDisabledStyle; dc.FillRect(style.background, bounds_); - DrawIconWithText(dc, image, text, bounds_, gridStyle_, style); + DrawIconWithText(dc, image, text, bounds_, gridStyle_ ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST, style); } -GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams) - : LinearLayout(ORIENT_VERTICAL, layoutParams), gridStyle_(gridStyle), browseFlags_(browseFlags), portrait_(portrait), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager), token_(token) { +GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, int *viewMode, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams) + : LinearLayout(ORIENT_VERTICAL, layoutParams), viewMode_(viewMode), browseFlags_(browseFlags), portrait_(portrait), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager), token_(token) { using namespace UI; path_.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); Path memstickRoot = GetSysDirectory(DIRECTORY_MEMSTICK_ROOT); @@ -580,8 +664,15 @@ void GameBrowser::SetSearchFilter(const std::string &filter, bool setKeyboardFoc search_.ApplySearchFilter(gameList_, setKeyboardFocus); } +GameBrowserViewMode GameBrowser::ViewMode() const { + if (*viewMode_ < (int)GameBrowserViewMode::GRID || *viewMode_ > (int)GameBrowserViewMode::LARGE_LIST) { + return GameBrowserViewMode::GRID; + } + return (GameBrowserViewMode)*viewMode_; +} + void GameBrowser::LayoutChange(UI::EventParams &e) { - *gridStyle_ = e.a == 0 ? true : false; + *viewMode_ = e.a; refreshPending_ = true; } @@ -683,7 +774,7 @@ void GameBrowser::Update() { void GameBrowser::Draw(UIContext &dc) { using namespace UI; - if (lastScale_ != g_Config.fGameGridScale || lastLayoutWasGrid_ != *gridStyle_) { + if (lastScale_ != g_Config.fGameGridScale || lastViewMode_ != ViewMode()) { refreshPending_ = true; } @@ -747,7 +838,8 @@ void GameBrowser::Refresh() { using namespace UI; lastScale_ = g_Config.fGameGridScale; - lastLayoutWasGrid_ = *gridStyle_; + lastViewMode_ = ViewMode(); + const bool gridStyle = lastViewMode_ == GameBrowserViewMode::GRID; // Kill all the contents Clear(); @@ -822,7 +914,8 @@ void GameBrowser::Refresh() { ChoiceStrip *layoutChoice = topBar->Add(new ChoiceStrip(ORIENT_HORIZONTAL)); layoutChoice->AddChoice(ImageID("I_GRID")); layoutChoice->AddChoice(ImageID("I_LINES")); - layoutChoice->SetSelection(*gridStyle_ ? 0 : 1, false); + layoutChoice->AddChoice(ImageID("I_LARGE_LIST")); + layoutChoice->SetSelection((int)lastViewMode_, false); layoutChoice->OnChoice.Handle(this, &GameBrowser::LayoutChange); topBar->Add(new Choice(ImageID("I_ROTATE_LEFT"), new LayoutParams(64.0f, 64.0f)))->OnClick.Add([=](UI::EventParams &e) { path_.Refresh(); @@ -830,7 +923,7 @@ void GameBrowser::Refresh() { }); topBar->Add(new Choice(ImageID("I_GEAR"), new LayoutParams(64.0f, 64.0f)))->OnClick.Handle(this, &GameBrowser::GridSettingsClick); - if (*gridStyle_) { + if (gridStyle) { gameList_ = new UI::GridLayoutList(UI::GridLayoutSettings(150 * g_Config.fGameGridScale, 85 * g_Config.fGameGridScale), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(10, 0, 6, 0))); } else { UI::LinearLayout *gl = new UI::LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); @@ -838,7 +931,7 @@ void GameBrowser::Refresh() { gameList_ = gl; } } else { - if (*gridStyle_) { + if (gridStyle) { gameList_ = new UI::GridLayoutList(UI::GridLayoutSettings(150 * g_Config.fGameGridScale, 85 * g_Config.fGameGridScale), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(10, 0, 6, 0))); } else { UI::LinearLayout *gl = new UI::LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); @@ -870,7 +963,7 @@ void GameBrowser::Refresh() { std::vector filenames; if (HasSpecialFiles(filenames)) { for (size_t i = 0; i < filenames.size(); i++) { - gameButtons.push_back(new GameButton(filenames[i], *gridStyle_, new UI::LinearLayoutParams(*gridStyle_ == true ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); + gameButtons.push_back(new GameButton(filenames[i], lastViewMode_, new UI::LinearLayoutParams(gridStyle ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); } } else if (!listingPending_) { std::vector fileInfo; @@ -888,10 +981,10 @@ void GameBrowser::Refresh() { if (!isGame && !isSaveData) { if (browseFlags_ & BrowseFlags::NAVIGATE) { - dirButtons.push_back(new DirButton(fileInfo[i].fullName, fileInfo[i].name, *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); + dirButtons.push_back(new DirButton(fileInfo[i].fullName, fileInfo[i].name, gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); } } else { - gameButtons.push_back(new GameButton(fileInfo[i].fullName, *gridStyle_, new UI::LinearLayoutParams(*gridStyle_ == true ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); + gameButtons.push_back(new GameButton(fileInfo[i].fullName, lastViewMode_, new UI::LinearLayoutParams(gridStyle ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); } } @@ -904,7 +997,7 @@ void GameBrowser::Refresh() { if (!fileInfo.empty()) { for (size_t i = 0; i < fileInfo.size(); i++) { if (!fileInfo[i].isDirectory) { - GameButton *b = new GameButton(fileInfo[i].fullName, *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)); + GameButton *b = new GameButton(fileInfo[i].fullName, lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)); b->SetHoldEnabled(false); gameButtons.push_back(b); } @@ -915,14 +1008,14 @@ void GameBrowser::Refresh() { if (browseFlags_ & BrowseFlags::NAVIGATE) { if (path_.CanNavigateUp()) { - gameList_->Add(new DirButton(Path(".."), *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> + gameList_->Add(new DirButton(Path(".."), gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> OnClick.Handle(this, &GameBrowser::NavigateClick); } // Add any pinned paths before other directories. auto pinnedPaths = GetPinnedPaths(); for (const auto &pinnedPath : pinnedPaths) { - DirButton *pinnedDir = gameList_->Add(new DirButton(pinnedPath, pinnedPath.GetFilename(), *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); + DirButton *pinnedDir = gameList_->Add(new DirButton(pinnedPath, pinnedPath.GetFilename(), gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); pinnedDir->OnClick.Handle(this, &GameBrowser::NavigateClick); pinnedDir->SetPinned(true); } @@ -950,7 +1043,7 @@ void GameBrowser::Refresh() { // Show a button to toggle pinning at the very end. if ((browseFlags_ & BrowseFlags::PIN) && !path_.GetPath().empty()) { std::string caption = ""; // IsCurrentPathPinned() ? "-" : "+"; - if (!*gridStyle_) { + if (!gridStyle) { caption = IsCurrentPathPinned() ? mm->T("UnpinPath", "Unpin") : mm->T("PinPath", "Pin"); } UI::Button *pinButton = gameList_->Add(new Button(caption, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); diff --git a/UI/GameBrowser.h b/UI/GameBrowser.h index 05c843b066..357cdde1d0 100644 --- a/UI/GameBrowser.h +++ b/UI/GameBrowser.h @@ -6,6 +6,7 @@ #include "Common/File/Path.h" #include "Common/UI/ViewGroup.h" #include "Common/File/PathBrowser.h" +#include "Core/ConfigValues.h" #include "UI/MiscViews.h" enum GameBrowserFlags { @@ -26,7 +27,7 @@ ENUM_CLASS_BITOPS(BrowseFlags); class GameBrowser : public UI::LinearLayout { public: - GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams = nullptr); + GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, int *viewMode, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams = nullptr); UI::Event OnChoice; UI::Event OnHoldChoice; @@ -53,6 +54,7 @@ protected: virtual Path HomePath(); void Refresh(); + GameBrowserViewMode ViewMode() const; Path homePath_; @@ -76,7 +78,7 @@ private: UI::ViewGroup *gameList_ = nullptr; PathBrowser path_; - bool *gridStyle_ = nullptr; + int *viewMode_ = nullptr; BrowseFlags browseFlags_; std::string lastText_; std::string lastLink_; @@ -87,7 +89,7 @@ private: bool listingPending_ = false; bool refreshPending_ = false; float lastScale_ = 1.0f; - bool lastLayoutWasGrid_ = true; + GameBrowserViewMode lastViewMode_ = GameBrowserViewMode::GRID; ScreenManager *screenManager_; int token_ = -1; bool portrait_ = false; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 85798c28e5..8779e22161 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -71,78 +71,27 @@ constexpr GameInfoFlags g_desiredFlags = GameInfoFlags::PARAM_SFO | GameInfoFlag class PMFView : public UI::InertView { public: - PMFView(std::string data, UI::LayoutParams *params) : UI::InertView(params), data_(data) { + PMFView(std::string data, UI::LayoutParams *params) : UI::InertView(params), video_(std::move(data)) { startTime_ = Instant::Now(); - player_ = pmf_create(); - if (0 == pmf_init(player_, (const uint8_t *)data_.data(), data_.size(), &width_, &height_)) { - - } else { - ERROR_LOG(Log::G3D, "Couldn't load pmf"); - pmf_destroy(player_); - player_ = nullptr; - } - } - - ~PMFView() { - if (curFrame_) { - curFrame_->Release(); - curFrame_ = nullptr; - } - - if (player_) { - pmf_destroy(player_); - player_ = nullptr; - } } void DeviceLost() override { - if (curFrame_) { - curFrame_->Release(); - curFrame_ = nullptr; - } + video_.DeviceLost(); } void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { // Just use the video size. - w = width_; - h = height_; + w = video_.Width(); + h = video_.Height(); } void Draw(UIContext &dc) override { - if (!player_) { - return; - } - - Draw::DrawContext *draw = dc.GetDrawContext(); - - // Dimensions are capped by pmf_init, but use size_t arithmetic anyway - // so a regression can't overflow the allocation. - std::vector frame((size_t)width_ * (size_t)height_ * 4); - if (pmf_update(player_, startTime_.ElapsedSeconds(), frame.data())) { - if (curFrame_) { - curFrame_->Release(); - curFrame_ = nullptr; - } - - Draw::TextureDesc desc{}; - desc.width = width_; - desc.height = height_; - desc.depth = 1; - desc.format = Draw::DataFormat::R8G8B8A8_UNORM; - desc.generateMips = false; - desc.tag = "pmf_frame"; - desc.type = Draw::TextureType::LINEAR2D; - desc.mipLevels = 1; - desc.initData.push_back(frame.data()); - - curFrame_ = draw->CreateTexture(desc); - } - - if (curFrame_) { + Draw::Texture *frame = video_.Update(dc.GetDrawContext(), startTime_.ElapsedSeconds()); + if (frame) { int dropsize = 5; dc.Draw()->DrawImage4Grid(dc.GetTheme().dropShadow4Grid, bounds_.x - dropsize * 1.5f, bounds_.y - dropsize * 1.5f, bounds_.x2() + dropsize * 1.5f, bounds_.y2() + dropsize * 1.5f, 0xFF000000, 1.0f); dc.Flush(); - draw->BindTexture(0, curFrame_); + dc.GetDrawContext()->BindTexture(0, frame); dc.Draw()->DrawTexRect(bounds_, 0, 0, 1.0f, 1.0f, 0xFFFFFFFF); dc.Flush(); } @@ -151,12 +100,8 @@ public: } private: - std::string data_; - Draw::Texture *curFrame_ = nullptr; - PMFPlayer *player_ = nullptr; + PMFVideoTexture video_; Instant startTime_; - int width_ = 0; - int height_ = 0; }; GameScreen::GameScreen(const Path &gamePath, bool inGame) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::SettingsToTheRight | TwoPaneFlags::CustomContextMenu), inGame_(inGame) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index c9524d1929..ff4b78b55d 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -177,7 +177,7 @@ void MainScreen::CreateRecentTab() { bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait; GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(), - Path("!RECENT"), BrowseFlags::NONE, portrait, &g_Config.bGridView1, screenManager(), "", "", + Path("!RECENT"), BrowseFlags::NONE, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "", new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); tabRecentGames->SetSearchBar(search); @@ -190,7 +190,7 @@ void MainScreen::CreateRecentTab() { tabRecentGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight); } -GameBrowser *MainScreen::CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, bool *bGridView, float *scrollPos) { +GameBrowser *MainScreen::CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, int *viewMode, float *scrollPos) { using namespace UI; auto mm = GetI18NCategory(I18NCat::MAINMENU); @@ -203,7 +203,7 @@ GameBrowser *MainScreen::CreateBrowserTab(const Path &path, std::string_view tit ScrollView *scrollView = tabContainer->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f))); scrollView->SetTag(title); // Re-use title as tag, should be fine. - GameBrowser *gameBrowser = new GameBrowser(GetRequesterToken(), path, browseFlags, portrait, bGridView, screenManager(), + GameBrowser *gameBrowser = new GameBrowser(GetRequesterToken(), path, browseFlags, portrait, viewMode, screenManager(), mm->T(howToTitle), howToUri, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); @@ -384,12 +384,12 @@ void MainScreen::CreateViews() { Button *focusButton = nullptr; if (hasStorageAccess) { - CreateBrowserTab(Path(g_Config.currentDirectory), "Games", "How to get games", getGamesUri, BrowseFlags::STANDARD, &g_Config.bGridView2, &g_Config.fGameListScrollPosition); - CreateBrowserTab(GetSysDirectory(DIRECTORY_GAME), "Homebrew & Demos", "How to get homebrew & demos", getHomebrewUri, BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, &g_Config.fHomebrewScrollPosition); + CreateBrowserTab(Path(g_Config.currentDirectory), "Games", "How to get games", getGamesUri, BrowseFlags::STANDARD, &g_Config.iGameBrowserView2, &g_Config.fGameListScrollPosition); + CreateBrowserTab(GetSysDirectory(DIRECTORY_GAME), "Homebrew & Demos", "How to get homebrew & demos", getHomebrewUri, BrowseFlags::HOMEBREW_STORE, &g_Config.iGameBrowserView3, &g_Config.fHomebrewScrollPosition); if (g_Config.bRemoteTab && !g_Config.sLastRemoteISOServer.empty()) { Path remotePath(FormatRemoteISOUrl(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort, RemoteSubdir().c_str())); - GameBrowser *remoteBrowser = CreateBrowserTab(remotePath, "Remote disc streaming", "Remote disc streaming", remoteGamesUri, BrowseFlags::NAVIGATE, &g_Config.bGridView4, &g_Config.fRemoteScrollPosition); + GameBrowser *remoteBrowser = CreateBrowserTab(remotePath, "Remote disc streaming", "Remote disc streaming", remoteGamesUri, BrowseFlags::NAVIGATE, &g_Config.iGameBrowserView4, &g_Config.fRemoteScrollPosition); remoteBrowser->SetHomePath(remotePath); } @@ -860,7 +860,7 @@ void UmdReplaceScreen::CreateViews() { 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.bGridView1, screenManager(), "", "", + Path("!RECENT"), BrowseFlags::NONE, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "", new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); scrollRecentGames->Add(tabRecentGames); leftColumn->AddTab(mm->T("Recent"), ImageID::invalid(), scrollRecentGames); @@ -870,7 +870,7 @@ void UmdReplaceScreen::CreateViews() { 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.bGridView2, screenManager(), + GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, portrait, &g_Config.iGameBrowserView2, screenManager(), mm->T("How to get games"), "https://www.ppsspp.org/getgames.html", new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); @@ -932,9 +932,11 @@ void GridSettingsPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { LinearLayout *items = new LinearLayoutList(ORIENT_VERTICAL); items->SetSpacing(0.0f); - items->Add(new CheckBox(&g_Config.bGridView1, sy->T("Display Recent on a grid"))); - items->Add(new CheckBox(&g_Config.bGridView2, sy->T("Display Games on a grid"))); - items->Add(new CheckBox(&g_Config.bGridView3, sy->T("Display Homebrew on a grid"))); + // Same order as GameBrowserViewMode. + static const char *viewModes[] = { "Grid", "List", "Large list" }; + items->Add(new PopupMultiChoice(&g_Config.iGameBrowserView1, mm->T("Recent"), viewModes, 0, ARRAY_SIZE(viewModes), I18NCat::SYSTEM, screenManager())); + items->Add(new PopupMultiChoice(&g_Config.iGameBrowserView2, mm->T("Games"), viewModes, 0, ARRAY_SIZE(viewModes), I18NCat::SYSTEM, screenManager())); + items->Add(new PopupMultiChoice(&g_Config.iGameBrowserView3, mm->T("Homebrew & Demos"), viewModes, 0, ARRAY_SIZE(viewModes), I18NCat::SYSTEM, screenManager())); static const char *defaultTabs[] = { "Recent", "Games", "Homebrew & Demos" }; PopupMultiChoice *beziersChoice = items->Add(new PopupMultiChoice(&g_Config.iDefaultTab, sy->T("Default tab"), defaultTabs, 0, ARRAY_SIZE(defaultTabs), I18NCat::MAINMENU, screenManager())); diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 3181606103..2a9178e76a 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -58,7 +58,7 @@ protected: void CreateViews() override; void CreateRecentTab(); - GameBrowser *CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, bool *bGridView, float *scrollPos); + GameBrowser *CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, int *viewMode, float *scrollPos); void CreateMainButtons(UI::ViewGroup *parent, bool vertical); void DrawBackground(UIContext &dc) override; diff --git a/UI/MiscViews.cpp b/UI/MiscViews.cpp index a97b8fbc6c..57eacf7134 100644 --- a/UI/MiscViews.cpp +++ b/UI/MiscViews.cpp @@ -14,6 +14,7 @@ #include "Common/UI/PopupScreens.h" #include "Core/Config.h" #include "GPU/Common/PresentationCommon.h" +#include "Core/Util/VideoPlayer.h" TextWithImage::TextWithImage(ImageID imageID, std::string_view text, UI::LinearLayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) { using namespace UI; @@ -509,3 +510,54 @@ bool ViewSearch::Key(UI::ViewGroup *viewGroup, const KeyInput &input) { } return retval; } + +PMFVideoTexture::PMFVideoTexture(std::string data) : data_(std::move(data)) { + player_ = pmf_create(); + if (pmf_init(player_, (const uint8_t *)data_.data(), data_.size(), &width_, &height_) != 0) { + ERROR_LOG(Log::G3D, "Couldn't load pmf"); + pmf_destroy(player_); + player_ = nullptr; + } +} + +PMFVideoTexture::~PMFVideoTexture() { + DeviceLost(); + if (player_) { + pmf_destroy(player_); + player_ = nullptr; + } +} + +void PMFVideoTexture::DeviceLost() { + if (curFrame_) { + curFrame_->Release(); + curFrame_ = nullptr; + } +} + +Draw::Texture *PMFVideoTexture::Update(Draw::DrawContext *draw, double timeSeconds) { + if (!player_) { + return nullptr; + } + + // Dimensions are capped by pmf_init, but use size_t arithmetic anyway + // so a regression can't overflow the allocation. + frame_.resize((size_t)width_ * (size_t)height_ * 4); + if (pmf_update(player_, timeSeconds, frame_.data())) { + DeviceLost(); + + Draw::TextureDesc desc{}; + desc.width = width_; + desc.height = height_; + desc.depth = 1; + desc.format = Draw::DataFormat::R8G8B8A8_UNORM; + desc.generateMips = false; + desc.tag = "pmf_frame"; + desc.type = Draw::TextureType::LINEAR2D; + desc.mipLevels = 1; + desc.initData.push_back(frame_.data()); + + curFrame_ = draw->CreateTexture(desc); + } + return curFrame_; +} diff --git a/UI/MiscViews.h b/UI/MiscViews.h index 709a7bf0da..50310bcf8c 100644 --- a/UI/MiscViews.h +++ b/UI/MiscViews.h @@ -132,3 +132,32 @@ struct ViewSearch { void ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus); bool Key(UI::ViewGroup *viewGroup, const KeyInput &input); }; + +struct PMFPlayer; +namespace Draw { +class DrawContext; +class Texture; +} + +// Decodes a PMF video (like a game's ICON1.PMF) into a texture, looping. +class PMFVideoTexture { +public: + explicit PMFVideoTexture(std::string data); + ~PMFVideoTexture(); + + bool IsValid() const { return player_ != nullptr; } + int Width() const { return width_; } + int Height() const { return height_; } + + // Returns the frame to show at the given time, or nullptr if none is decoded yet. + Draw::Texture *Update(Draw::DrawContext *draw, double timeSeconds); + void DeviceLost(); + +private: + std::string data_; + std::vector frame_; + Draw::Texture *curFrame_ = nullptr; + PMFPlayer *player_ = nullptr; + int width_ = 0; + int height_ = 0; +}; diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 5e4a1739a1..3ba4d47d44 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -615,7 +615,7 @@ void RemoteISOBrowseScreen::CreateViews() { ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollRecentGames->SetTag("RemoteGamesTab"); GameBrowser *tabRemoteGames = new GameBrowser(GetRequesterToken(), - Path(url_), BrowseFlags::NAVIGATE, portrait, &g_Config.bGridView1, screenManager(), "", "", + Path(url_), BrowseFlags::NAVIGATE, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "", new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); tabRemoteGames->SetHomePath(Path(url_)); diff --git a/UI/UIAtlas.cpp b/UI/UIAtlas.cpp index 5f68300638..3430114e95 100644 --- a/UI/UIAtlas.cpp +++ b/UI/UIAtlas.cpp @@ -76,6 +76,7 @@ static const ImageMeta g_uiImageIDs[] = { {"I_DROP_SHADOW", false}, {"I_LINES", false}, {"I_GRID", false}, + {"I_LARGE_LIST", false}, {"I_LOGO", false}, {"I_ICON", false}, {"I_ICON_GOLD", false}, diff --git a/assets/ui_images/images.svg b/assets/ui_images/images.svg index 13b8100a8d..cdb8c159e2 100644 --- a/assets/ui_images/images.svg +++ b/assets/ui_images/images.svg @@ -3,8 +3,8 @@ .st0{fill:#000000;} - + From 7d273e178fa5618d324128f13c7549f06d42ab87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 10:33:04 +0200 Subject: [PATCH 2/8] Game browser: Info button in the large list, long press with buttons Each line in the large list gets an info button, doing the same as a long press or right click. Holding the accept button now works as a long press in all view modes, so it can be done from a gamepad. Rename "Grid icon size" to "Icon size", since it now also applies to the large list. Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/GameBrowser.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++-- UI/MainScreen.cpp | 2 +- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index e5df693610..a043120826 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -54,6 +54,7 @@ static constexpr float LARGE_LIST_ICON_W = 144.0f; static constexpr float LARGE_LIST_ICON_H = 80.0f; static constexpr float LARGE_LIST_PAD = 6.0f; +static constexpr float LARGE_LIST_INFO_SIZE = 64.0f; // Where the text starts in the list modes. static float ListTextX(GameBrowserViewMode viewMode) { @@ -63,6 +64,14 @@ static float ListTextX(GameBrowserViewMode viewMode) { return 150.0f; } +// Space to the right of the text in the list modes, for the info button. +static float ListTextRightMargin(GameBrowserViewMode viewMode) { + if (viewMode == GameBrowserViewMode::LARGE_LIST) { + return LARGE_LIST_INFO_SIZE + LARGE_LIST_PAD * 2; + } + return 0.0f; +} + static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text, const Bounds &bounds, GameBrowserViewMode viewMode, const UI::Style &style) { const bool gridStyle = viewMode == GameBrowserViewMode::GRID; float tw, th; @@ -106,7 +115,7 @@ static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text } float tx = textX; - int availableWidth = bounds.w - textX; + int availableWidth = bounds.w - textX - ListTextRightMargin(viewMode); float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; if (availableWidth < tw) { tx -= (1.0f + sin(time_now_d() * 1.5f)) * sineWidth; @@ -158,8 +167,11 @@ public: holdEnabled_ = hold; } bool Touch(const TouchInput &input) override { - const bool retval = UI::Clickable::Touch(input); hovering_ = bounds_.Contains(input.x, input.y); + if (HasInfoButton() && TouchInfoButton(input)) { + return true; + } + const bool retval = UI::Clickable::Touch(input); if (hovering_ && (input.flags & TouchInputFlags::DOWN)) { holdStart_ = time_now_d(); } @@ -197,6 +209,16 @@ public: return true; } + // Holding the accept button works like a long press, so a gamepad can do it too. + if (holdEnabled_ && HasFocus() && UI::IsAcceptKey(key) && !(key.flags & KeyInputFlags::IS_REPEAT)) { + if (key.flags & KeyInputFlags::DOWN) { + holdStart_ = time_now_d(); + } + if (key.flags & KeyInputFlags::UP) { + holdStart_ = 0.0; + } + } + return Clickable::Key(key); } @@ -209,6 +231,10 @@ public: void FocusChanged(UI::FocusFlags focusFlags) override { UI::Clickable::FocusChanged(focusFlags); + if (focusFlags & UI::FocusFlags::LOST_FOCUS) { + // Don't let a held accept button carry over from a button we've left. + holdStart_ = 0.0; + } TriggerOnHighlight(focusFlags); } @@ -240,6 +266,34 @@ private: void UpdateVideo(const std::shared_ptr &ginfo, bool wantVideo); + // The large list has room for an info button on each line, doing the same as a long press. + bool HasInfoButton() const { + return viewMode_ == GameBrowserViewMode::LARGE_LIST && holdEnabled_; + } + Bounds InfoButtonBounds() const { + return Bounds(bounds_.x2() - LARGE_LIST_INFO_SIZE - LARGE_LIST_PAD, bounds_.centerY() - LARGE_LIST_INFO_SIZE * 0.5f, LARGE_LIST_INFO_SIZE, LARGE_LIST_INFO_SIZE); + } + // Returns true if the info button took the input. + bool TouchInfoButton(const TouchInput &input) { + if ((input.flags & TouchInputFlags::MOUSE) && (input.buttons & 1) == 0) { + return false; + } + const bool inside = InfoButtonBounds().Contains(input.x, input.y); + if (input.flags & TouchInputFlags::DOWN) { + infoButtonDown_ = inside; + } + if (!infoButtonDown_) { + return false; + } + if (input.flags & TouchInputFlags::UP) { + infoButtonDown_ = false; + if (inside && !(input.flags & TouchInputFlags::CANCEL)) { + TriggerOnHoldClick(); + } + } + return true; + } + GameBrowserViewMode viewMode_; bool gridStyle_; Path gamePath_; @@ -254,6 +308,7 @@ private: bool showInfoPressed_ = false; bool infoKeyPressed_ = false; bool hovering_ = false; + bool infoButtonDown_ = false; }; void GameButton::UpdateVideo(const std::shared_ptr &ginfo, bool wantVideo) { @@ -476,7 +531,7 @@ void GameButton::Draw(UIContext &dc) { dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_, &tw, &th, 0); - int availableWidth = bounds_.w - textX; + int availableWidth = bounds_.w - textX - ListTextRightMargin(viewMode_); if (g_Config.bShowIDOnGameIcon) { float vw, vh; dc.MeasureText(dc.GetFontStyle(), 0.7f, 0.7f, ginfo->id_version, &vw, &vh, 0); @@ -549,6 +604,16 @@ void GameButton::Draw(UIContext &dc) { } } + if (HasInfoButton()) { + const Bounds infoBounds = InfoButtonBounds(); + Style infoStyle = HasFocus() ? dc.GetTheme().itemFocusedStyle : dc.GetTheme().itemStyle; + if (infoButtonDown_) { + infoStyle = dc.GetTheme().itemDownStyle; + dc.FillRect(infoStyle.background, infoBounds); + } + dc.Draw()->DrawImage(ImageID("I_INFO"), infoBounds.centerX(), infoBounds.centerY(), 1.0f, infoStyle.fgColor, ALIGN_CENTER); + } + if (overlayColor) { dc.FillRect(Drawable(overlayColor), overlayBounds); } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index ff4b78b55d..d2a5989a76 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -940,7 +940,7 @@ void GridSettingsPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { static const char *defaultTabs[] = { "Recent", "Games", "Homebrew & Demos" }; PopupMultiChoice *beziersChoice = items->Add(new PopupMultiChoice(&g_Config.iDefaultTab, sy->T("Default tab"), defaultTabs, 0, ARRAY_SIZE(defaultTabs), I18NCat::MAINMENU, screenManager())); - items->Add(new ItemHeader(sy->T("Grid icon size"))); + items->Add(new ItemHeader(sy->T("Icon size"))); items->Add(new Choice(sy->T("Increase size")))->OnClick.Handle(this, &GridSettingsPopupScreen::GridPlusClick); items->Add(new Choice(sy->T("Decrease size")))->OnClick.Handle(this, &GridSettingsPopupScreen::GridMinusClick); From 43704b215c102a50496292a1c34e4fd5c72754db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 10:45:12 +0200 Subject: [PATCH 3/8] Game browser: Keyboard focus for the info button, more left padding In the large list, right and left move between a game and its info button, so up and down still step from game to game. Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/GameBrowser.cpp | 53 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index a043120826..5e6d9a602f 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -54,12 +54,13 @@ static constexpr float LARGE_LIST_ICON_W = 144.0f; static constexpr float LARGE_LIST_ICON_H = 80.0f; static constexpr float LARGE_LIST_PAD = 6.0f; +static constexpr float LARGE_LIST_LEFT_PAD = 11.0f; static constexpr float LARGE_LIST_INFO_SIZE = 64.0f; // Where the text starts in the list modes. static float ListTextX(GameBrowserViewMode viewMode) { if (viewMode == GameBrowserViewMode::LARGE_LIST) { - return LARGE_LIST_PAD + LARGE_LIST_ICON_W * g_Config.fGameGridScale + 20.0f; + return LARGE_LIST_LEFT_PAD + LARGE_LIST_ICON_W * g_Config.fGameGridScale + 20.0f; } return 150.0f; } @@ -109,7 +110,7 @@ static void DrawIconWithText(UIContext &dc, ImageID image, std::string_view text const float textX = ListTextX(viewMode); if (viewMode == GameBrowserViewMode::LARGE_LIST) { const float scale = g_Config.fGameGridScale; - dc.Draw()->DrawImage(image, bounds.x + LARGE_LIST_PAD + LARGE_LIST_ICON_W * 0.5f * scale, bounds.centerY(), 0.88f * scale, style.fgColor, ALIGN_CENTER); + dc.Draw()->DrawImage(image, bounds.x + LARGE_LIST_LEFT_PAD + LARGE_LIST_ICON_W * 0.5f * scale, bounds.centerY(), 0.88f * scale, style.fgColor, ALIGN_CENTER); } else { dc.Draw()->DrawImage(image, bounds.x + 72, bounds.centerY(), 0.88f * (gridStyle ? g_Config.fGameGridScale : 1.0), style.fgColor, ALIGN_CENTER); } @@ -209,6 +210,17 @@ public: return true; } + if (infoSelected_ && HasFocus() && UI::IsAcceptKey(key)) { + if (key.flags & KeyInputFlags::DOWN) { + infoButtonDown_ = true; + } + if ((key.flags & KeyInputFlags::UP) && infoButtonDown_) { + infoButtonDown_ = false; + TriggerOnHoldClick(); + } + return true; + } + // Holding the accept button works like a long press, so a gamepad can do it too. if (holdEnabled_ && HasFocus() && UI::IsAcceptKey(key) && !(key.flags & KeyInputFlags::IS_REPEAT)) { if (key.flags & KeyInputFlags::DOWN) { @@ -234,10 +246,32 @@ public: if (focusFlags & UI::FocusFlags::LOST_FOCUS) { // Don't let a held accept button carry over from a button we've left. holdStart_ = 0.0; + // Moving to another game selects the game, not its info button. + infoSelected_ = false; + infoButtonDown_ = false; } TriggerOnHighlight(focusFlags); } + // Left and right move between the game and its info button, so up and down still go from game to game. + bool CanMoveFocus(UI::FocusMove dir) const override { + if (!HasInfoButton()) { + return true; + } + // We handle these moves ourselves, so MoveFocus won't play the sound for them. + if (dir == UI::FocusMove::RIGHT && !infoSelected_) { + infoSelected_ = true; + UI::PlayUISound(UI::UISound::SELECT); + return false; + } + if (dir == UI::FocusMove::LEFT && infoSelected_) { + infoSelected_ = false; + UI::PlayUISound(UI::UISound::SELECT); + return false; + } + return true; + } + void DeviceLost() override { if (video_) { video_->DeviceLost(); @@ -309,6 +343,8 @@ private: bool infoKeyPressed_ = false; bool hovering_ = false; bool infoButtonDown_ = false; + // The info button has the keyboard focus, rather than the game. Changed from CanMoveFocus, hence mutable. + mutable bool infoSelected_ = false; }; void GameButton::UpdateVideo(const std::shared_ptr &ginfo, bool wantVideo) { @@ -414,15 +450,16 @@ void GameButton::Draw(UIContext &dc) { int w = gridStyle_ ? bounds_.w : 144; int h = bounds_.h; if (largeList) { - x += LARGE_LIST_PAD; + x += LARGE_LIST_LEFT_PAD; y += LARGE_LIST_PAD; w = LARGE_LIST_ICON_W * g_Config.fGameGridScale; h = LARGE_LIST_ICON_H * g_Config.fGameGridScale; } const float textX = ListTextX(viewMode_); + const bool rowFocused = HasFocus() && !infoSelected_; if (!gridStyle_ || !texture) { - if (HasFocus()) + if (rowFocused) style = down_ ? dc.GetTheme().itemDownStyle : dc.GetTheme().itemFocusedStyle; Drawable bg = style.background; @@ -501,7 +538,7 @@ void GameButton::Draw(UIContext &dc) { if (imageIcon.isValid()) { Style style = dc.GetTheme().itemStyle; - if (HasFocus()) style = dc.GetTheme().itemFocusedStyle; + if (rowFocused) style = dc.GetTheme().itemFocusedStyle; if (down_) style = dc.GetTheme().itemDownStyle; if (!IsEnabled()) style = dc.GetTheme().itemDisabledStyle; @@ -573,7 +610,7 @@ void GameButton::Draw(UIContext &dc) { if (gridStyle_) { dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x, y + h - gearImage->h * g_Config.fGameGridScale, g_Config.fGameGridScale); } else if (largeList) { - dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + LARGE_LIST_PAD, y + h - gearImage->h * g_Config.fGameGridScale, g_Config.fGameGridScale); + dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + LARGE_LIST_LEFT_PAD, y + h - gearImage->h * g_Config.fGameGridScale, g_Config.fGameGridScale); } else { dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + 4, y, 1.0f); } @@ -596,7 +633,7 @@ void GameButton::Draw(UIContext &dc) { dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + bounds_.w - (image->w + 5) * g_Config.fGameGridScale, y + h - (image->h + 5) * g_Config.fGameGridScale, g_Config.fGameGridScale); } else if (largeList) { - dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + LARGE_LIST_PAD + (LARGE_LIST_ICON_W - image->w - 5) * g_Config.fGameGridScale, + dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + LARGE_LIST_LEFT_PAD + (LARGE_LIST_ICON_W - image->w - 5) * g_Config.fGameGridScale, y + h - (image->h + 5) * g_Config.fGameGridScale, g_Config.fGameGridScale); } else { dc.Draw()->DrawImage(regionIcons[regionIndex], bounds_.x + 4, y + h - image->h - 5, 1.0f); @@ -610,6 +647,8 @@ void GameButton::Draw(UIContext &dc) { if (infoButtonDown_) { infoStyle = dc.GetTheme().itemDownStyle; dc.FillRect(infoStyle.background, infoBounds); + } else if (HasFocus() && infoSelected_) { + dc.FillRect(infoStyle.background, infoBounds); } dc.Draw()->DrawImage(ImageID("I_INFO"), infoBounds.centerX(), infoBounds.centerY(), 1.0f, infoStyle.fgColor, ALIGN_CENTER); } From 524e8b5254b5e69023d1d3e687bdd174080270b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 10:46:40 +0200 Subject: [PATCH 4/8] Translations: Game browser view modes, "Icon size" "Grid icon size" is renamed to "Icon size", keeping the translations with "grid" dropped from them. New keys for the view mode choices. Co-Authored-By: Claude Opus 5.5 (1M context) --- assets/lang/ar_AE.ini | 5 ++++- assets/lang/az_AZ.ini | 5 ++++- assets/lang/be_BY.ini | 5 ++++- assets/lang/bg_BG.ini | 5 ++++- assets/lang/ca_ES.ini | 5 ++++- assets/lang/cz_CZ.ini | 5 ++++- assets/lang/da_DK.ini | 5 ++++- assets/lang/de_DE.ini | 5 ++++- assets/lang/dr_ID.ini | 5 ++++- assets/lang/en_US.ini | 5 ++++- assets/lang/es_ES.ini | 5 ++++- assets/lang/es_LA.ini | 5 ++++- assets/lang/fa_IR.ini | 5 ++++- assets/lang/fi_FI.ini | 5 ++++- assets/lang/fr_FR.ini | 5 ++++- assets/lang/gl_ES.ini | 5 ++++- assets/lang/gr_EL.ini | 5 ++++- assets/lang/he_IL.ini | 5 ++++- assets/lang/he_IL_invert.ini | 5 ++++- assets/lang/hr_HR.ini | 5 ++++- assets/lang/hu_HU.ini | 5 ++++- assets/lang/id_ID.ini | 5 ++++- assets/lang/it_IT.ini | 5 ++++- assets/lang/ja_JP.ini | 5 ++++- assets/lang/jv_ID.ini | 5 ++++- assets/lang/km_KH.ini | 5 ++++- assets/lang/ko_KR.ini | 5 ++++- assets/lang/ku_SO.ini | 5 ++++- assets/lang/lo_LA.ini | 5 ++++- assets/lang/lt-LT.ini | 5 ++++- assets/lang/ms_MY.ini | 5 ++++- assets/lang/nl_NL.ini | 5 ++++- assets/lang/nn_NO.ini | 5 ++++- assets/lang/no_NO.ini | 5 ++++- assets/lang/pl_PL.ini | 5 ++++- assets/lang/pt_BR.ini | 5 ++++- assets/lang/pt_PT.ini | 5 ++++- assets/lang/ro_RO.ini | 5 ++++- assets/lang/ru_RU.ini | 5 ++++- assets/lang/sv_SE.ini | 5 ++++- assets/lang/tg_PH.ini | 5 ++++- assets/lang/th_TH.ini | 5 ++++- assets/lang/tr_TR.ini | 5 ++++- assets/lang/uk_UA.ini | 5 ++++- assets/lang/vi_VN.ini | 5 ++++- assets/lang/zh_CN.ini | 5 ++++- assets/lang/zh_TW.ini | 5 ++++- 47 files changed, 188 insertions(+), 47 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 5747c69c3e..ed8864a459 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -1429,10 +1429,14 @@ Failed to load state for load undo. Error in the file system. = فشل تحمي Final processed image = الصورة النهائية المعالجة # AI translated Floating symbols = رموز عائمة # AI translated Game crashed = تعطلت اللعبة # AI translated +Grid = شبكة # AI translated Hide navigation bar = إخفاء شريط التنقل # AI translated I/O timing method = طريقة توقيت الإدخال/الإخراج # AI translated +Icon size = حجم الأيقونات # AI translated JIT using IR = JIT باستخدام IR # AI translated Language = ‎اللغة +Large list = قائمة كبيرة # AI translated +List = قائمة # AI translated Loaded plugin: %1 = تم تحميل الإضافة: %1 # AI translated Memory Stick folder = مجلد شريحة الذاكرة # AI translated Memory Stick in installed.txt = ‎installed.txt مسار الحفظ في @@ -1463,7 +1467,6 @@ Fast Memory = ‎الذاكرة السريعة (غير ثابت) Force real clock sync (slower, less lag) = فرض مزامنة الساعة الحقيقية (أبطأ، تأخير أقل) # AI translated Games list settings = إعدادات قائمة الألعاب # AI translated General = ‎العام -Grid icon size = حجم أيقونات الشبكة # AI translated Help the PPSSPP team = ‎ساعد فريق البرنامج Host (bugs, less lag) = المضيف (مشاكل، تأخير أقل) # AI translated Ignore bad memory accesses = تجاهل الوصول السيئ للذاكرة # AI translated diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 73bee39fac..8e26c08861 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -1417,10 +1417,14 @@ Failed to load state for load undo. Error in the file system. = Geri yükləniş Final processed image = Son işlənmiş görüntü Floating symbols = Üzən simgələr Game crashed = Oyun çökdü +Grid = Tor # AI translated Hide navigation bar = Yönəliş çubuğunu gizlət I/O timing method = G/Ç zamanlama yöntəmi +Icon size = Simgə ölçüsü # AI translated JIT using IR = IR işlədən JIT Language = Dil +Large list = Böyük siyahı # AI translated +List = Siyahı # AI translated Loaded plugin: %1 = Yüklənən qoşma: %1 Memory Stick folder = Yaddaş Çubuğu qovluğu Memory Stick in installed.txt = Installed.txt'dəki Yaddaş Çubuğu @@ -1451,7 +1455,6 @@ Fast Memory = Sürətli Yaddaş (qalıcı deyil) Force real clock sync (slower, less lag) = Gerçək saat sinxini gücəndir (yavaş, az ilişmə) Games list settings = Oyun sıralığı quruluşları General = Toplam -Grid icon size = Torcuğun simgə ölçüsü Help the PPSSPP team = PPSSPP komandasına yardım et Host (bugs, less lag) = Sahib (yanlışlar, az ilişmə) Ignore bad memory accesses = Pis yaddaş girişlərini yox say diff --git a/assets/lang/be_BY.ini b/assets/lang/be_BY.ini index f33dc63691..0e659fa992 100644 --- a/assets/lang/be_BY.ini +++ b/assets/lang/be_BY.ini @@ -1403,9 +1403,13 @@ Daylight savings = Летні час Default tab = Укладка па змаўчанні Dynarec/JIT (recommended) = Dynarec/JIT (рэкамендуецца) Final processed image = Канчаткова апрацаванае выява +Grid = Сетка # AI translated Hide navigation bar = Схаваць панэль навігацыі # AI translated I/O timing method = Метад сінхранізацыі ўводу-вываду +Icon size = Памер значкоў # AI translated JIT using IR = JIT з выкарыстаннем IR +Large list = Вялікі спіс # AI translated +List = Спіс # AI translated Loaded plugin: %1 = Загружаны плагін: %1 Memory Stick folder = Тэчка карты памяці Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1441,7 +1445,6 @@ Force real clock sync (slower, less lag) = Прымусовая сінхрані Game crashed = Гульня зламалася Games list settings = Налады спісу гульняў General = Агульныя -Grid icon size = Памер значкоў сеткі Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Хост (памылкі, менш затрымкі) Ignore bad memory accesses = Ігнараваць няправільны доступ да памяці diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 8f95eb056f..96a114eaf6 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Инсталацията на фърмуера не бе успешна # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Мрежа # AI translated Hide navigation bar = Скрий навигационната лента # AI translated I/O timing method = I/O timing method +Icon size = Размер на иконите # AI translated Install or upgrade firmware from game discs = Инсталиране или обновяване на фърмуера от дисковете с игри # AI translated Installed firmware = Фърмуерът е инсталиран # AI translated Installing firmware = Инсталиране на фърмуер # AI translated JIT using IR = JIT using IR Language = Език +Large list = Голям списък # AI translated Launch XMB = Стартирай XMB # AI translated +List = Списък # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Бърза памет (нестабилно) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) Games list settings = Games list settings General = Основни -Grid icon size = Размер на иконата на мрежата Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 577232e64f..76b6d07d41 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Ha fallat la instal·lació del firmware # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Quadrícula # AI translated Hide navigation bar = Amaga la barra de navegació # AI translated I/O timing method = I/O timing method +Icon size = Icon size Install or upgrade firmware from game discs = Instal·la o actualitza el firmware des dels discs de jocs # AI translated Installed firmware = Firmware instal·lat # AI translated Installing firmware = S'està instal·lant el firmware # AI translated JIT using IR = JIT using IR Language = Llengua +Large list = Llista gran # AI translated Launch XMB = Iniciar l'XMB # AI translated +List = Llista # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Memòria ràpida (inestable) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) Games list settings = Games list settings General = General -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 21267caddc..7a54296c21 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Instalace firmwaru selhala # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Mřížka # AI translated Hide navigation bar = Skrýt navigační lištu # AI translated I/O timing method = Metoda časování vstupu/výstupu +Icon size = Icon size Install or upgrade firmware from game discs = Instalovat nebo aktualizovat firmware z herních disků # AI translated Installed firmware = Firmware nainstalován # AI translated Installing firmware = Instalace firmwaru # AI translated JIT using IR = JIT using IR Language = Jazyk +Large list = Velký seznam # AI translated Launch XMB = Spustit XMB # AI translated +List = Seznam # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Cesta pro uložení dat je installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Rychlá paměť (nestabilní) Force real clock sync (slower, less lag) = Vynutit skutečný soulad hodin (pomalejší, méně sekání) Games list settings = Games list settings General = Obecné -Grid icon size = Grid icon size Help the PPSSPP team = Pomozte týmu PPSSPP Host (bugs, less lag) = Hostitel (chyby, zasekává se méně) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 4b55057f24..8767911560 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Installation af firmware mislykkedes # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Gitter # AI translated Hide navigation bar = Skjul navigationslinjen # AI translated I/O timing method = I/O timing metode +Icon size = Icon size Install or upgrade firmware from game discs = Installer eller opdater firmware fra spildiske # AI translated Installed firmware = Firmware installeret # AI translated Installing firmware = Installerer firmware # AI translated JIT using IR = JIT using IR Language = Sprog +Large list = Stor liste # AI translated Launch XMB = Start XMB # AI translated +List = Liste # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Gem sti i installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Hurtig hukommelse (ustabil) Force real clock sync (slower, less lag) = Tving rigtig clock sync (langsommere, færre forsinkelser) Games list settings = Games list settings General = Generel -Grid icon size = Grid icon size Help the PPSSPP team = Hjælp PPSSPP holdet Host (bugs, less lag) = Host (fejl, færre forsinkelser) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 7a9ed54960..f8cda7338c 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -1423,14 +1423,18 @@ Final processed image = Endgültig verarbeitetes Bild Firmware installation failed = Firmware-Installation fehlgeschlagen # AI translated Floating symbols = Schwebende Symbole Game crashed = Spiel abgestürzt +Grid = Raster # AI translated Hide navigation bar = Navigationsleiste ausblenden I/O timing method = I/O Timing Methode +Icon size = Symbolgröße # AI translated Install or upgrade firmware from game discs = Firmware von Spiel-Discs installieren oder aktualisieren # AI translated Installed firmware = Firmware installiert # AI translated Installing firmware = Installiere Firmware # AI translated JIT using IR = JIT benutzt IR Language = Sprache +Large list = Große Liste # AI translated Launch XMB = XMB starten # AI translated +List = Liste # AI translated Loaded plugin: %1 = Plugin geladen: %1 Memory Stick folder = Memory-Stick-Ordner Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1461,7 +1465,6 @@ Fast Memory = Schneller Speicher (instabil) Force real clock sync (slower, less lag) = Echte Taktsync erzwingen (langsamer, weniger Verzögerung) Games list settings = Spielliste-Einstellungen General = Allgemein -Grid icon size = Rastersymbolgröße Help the PPSSPP team = Dem PPSSPP-Team helfen Host (bugs, less lag) = Host (Fehlerbehaftet, weniger Verzögerung) Ignore bad memory accesses = Fehlerhafte Speicherzugriffe ignorieren diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index dcb78548bb..a53f625a80 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -1416,10 +1416,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grid Hide navigation bar = Sembunyikan bilah navigasi # AI translated I/O timing method = I/O timing method +Icon size = Icon size JIT using IR = JIT using IR Language = Bahasa +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1450,7 +1454,6 @@ Fast Memory = Memori malassi (tang stabil) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) Games list settings = Games list settings General = Yato biasa -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 1ad24b047b..7006f5d586 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -1437,14 +1437,18 @@ Default tab = Default tab Dynarec/JIT (recommended) = Dynarec/JIT (recommended) Final processed image = Final processed image Firmware installation failed = Firmware installation failed +Grid = Grid Hide navigation bar = Hide navigation bar Hide status bar = Hide status bar I/O timing method = I/O timing method +Icon size = Icon size Install or upgrade firmware from game discs = Install or upgrade firmware from game discs Installed firmware = Installed firmware Installing firmware = Installing firmware JIT using IR = JIT using IR +Large list = Large list Launch XMB = Launch XMB +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1480,7 +1484,6 @@ Force real clock sync (slower, less lag) = Force real clock sync (slower, less l Game crashed = Game crashed Games list settings = Games list settings General = General -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index e2d6a7d441..c99b5df93b 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -1450,11 +1450,12 @@ Force real clock sync (slower, less lag) = Forzar sincronización de velocidad r Game crashed = El juego se bloqueó Games list settings = Ajustes de lista de juegos General = General -Grid icon size = Tamaño de iconos +Grid = Cuadrícula # AI translated Help the PPSSPP team = Ayuda al equipo de PPSSPP Hide navigation bar = Ocultar barra de navegación # AI translated Host (bugs, less lag) = Anfitrión (errores, menos retraso) I/O timing method = Método de sincronización de E/S +Icon size = Tamaño de iconos Ignore bad memory accesses = Ignorar accesos erróneos a memoria Increase size = Aumentar tamaño Install or upgrade firmware from game discs = Instalar o actualizar el firmware desde los discos de juego # AI translated @@ -1464,7 +1465,9 @@ Interpreter = Intérprete IR Interpreter = Intérprete IR JIT using IR = JIT usando IR Language = Idioma +Large list = Lista grande # AI translated Launch XMB = Iniciar el XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Plugin cargado: %1 Memory Stick folder = Carpeta de Memory Stick Memory Stick Folder = Carpeta de Memory Stick diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 41bedb09fb..f07af76e61 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1426,14 +1426,18 @@ Final processed image = Final processed image Firmware installation failed = Error al instalar el firmware # AI translated Floating symbols = Símbolos flotantes Game crashed = El juego crasheo +Grid = Cuadrícula # AI translated Hide navigation bar = Ocultar barra de navegación # AI translated I/O timing method = Método de sincronización de E/S +Icon size = Tamaño de iconos # AI translated Install or upgrade firmware from game discs = Instalar o actualizar el firmware desde los discos de juego # AI translated Installed firmware = Firmware instalado # AI translated Installing firmware = Instalando firmware # AI translated JIT using IR = JIT using IR Language = Idioma +Large list = Lista grande # AI translated Launch XMB = Iniciar el XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Plugin cargado: %1 Memory Stick folder = Carpeta del Memory Stick Memory Stick in installed.txt = Memory Stick en installed.txt @@ -1464,7 +1468,6 @@ Fast Memory = Memoria Rápida (inestable) Force real clock sync (slower, less lag) = Forzar sinc. real de reloj (lento, menos lag) Games list settings = Configuración de la lista de juegos General = General -Grid icon size = Tamaño de icono de cuadrícula Help the PPSSPP team = Ayuda al equipo de PPSSPP Host (bugs, less lag) = Anfitrión (con bugs pero menos lag) Ignore bad memory accesses = Ignorar malos accesos a la memoria diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 1eae64897f..591ed80705 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -1418,10 +1418,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = شبکه # AI translated Hide navigation bar = مخفی کردن نوار ناوبری # AI translated I/O timing method = ‎(ورودی/خروجی) I/O روش زمان بندی +Icon size = Icon size JIT using IR = JIT using IR Language = ‎زبان +Large list = فهرست بزرگ # AI translated +List = فهرست # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1452,7 +1456,6 @@ Fast Memory = ‎(مموری سریع (ناپایدار Force real clock sync (slower, less lag) = ‎واقعی (کندتر، لگ کمتر) CPU اجبار به همگام سازی سرعت Games list settings = لیست تنظیمات بازی General = ‎عمومی -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = ‎دستگاه (دارای باگ، لگ کمتر) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 5e6f4d7d46..88f8a14725 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Laiteohjelmiston asennus epäonnistui # AI translated Floating symbols = Leijuvat symbolit Game crashed = Peli kaatui +Grid = Ruudukko # AI translated Hide navigation bar = Piilota navigointipalkki # AI translated I/O timing method = I/O-aikamenetelmä +Icon size = Kuvakkeiden koko # AI translated Install or upgrade firmware from game discs = Asenna tai päivitä laiteohjelmisto pelilevyiltä # AI translated Installed firmware = Laiteohjelmisto asennettu # AI translated Installing firmware = Asennetaan laiteohjelmistoa # AI translated JIT using IR = JIT using IR Language = Kieli +Large list = Suuri luettelo # AI translated Launch XMB = Käynnistä XMB # AI translated +List = Luettelo # AI translated Loaded plugin: %1 = Ladattu liitännäinen: %1 Memory Stick folder = Muistikortin kansio Memory Stick in installed.txt = Tallennuskansio installed.txt-tiedostossa @@ -1462,7 +1466,6 @@ Fast Memory = Nopea muisti Force real clock sync (slower, less lag) = Pakota todellinen kellon synkronointi (hidastaa, vähemmän viivettä) Games list settings = Peliluettelon asetukset General = Yleiset -Grid icon size = Ruudukon kuvakkeen koko Help the PPSSPP team = Auta PPSSPP-tiimiä Host (bugs, less lag) = Isäntä (enemmän virheitä, vähemmän viivettä) Ignore bad memory accesses = Ohita huonot muistipääsyt diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 02d4cc8d2f..285e00858f 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -1439,13 +1439,17 @@ Dynarec/JIT (recommended) = Dynarec/JIT (recommandé) Error: load undo state is from a different game = Error: load undo state is from a different game Final processed image = Image finale traitée Firmware installation failed = Échec de l'installation du firmware # AI translated +Grid = Grille # AI translated Hide navigation bar = Masquer la barre de navigation I/O timing method = Méthode synchro. E/S +Icon size = Taille des icônes Install or upgrade firmware from game discs = Installer ou mettre à jour le firmware depuis les disques de jeu # AI translated Installed firmware = Firmware installé # AI translated Installing firmware = Installation du firmware # AI translated JIT using IR = JIT utilisant l'IR +Large list = Grande liste # AI translated Launch XMB = Lancer le XMB # AI translated +List = Liste # AI translated Loaded plugin: %1 = Plugin chargé : %1 Memory Stick folder = Changer le dossier de la Memory Stick Memory Stick in installed.txt = Chemin de sauvegarde dans "installed.txt" @@ -1480,7 +1484,6 @@ Force real clock sync (slower, less lag) = Forcer synchronisation temps réel (+ Game crashed = Le jeu a planté Games list settings = Paramètres des listes de jeux General = Général -Grid icon size = Taille des icônes Help the PPSSPP team = Aider l'équipe de PPSSPP Host (bugs, less lag) = Hôte (bugs, moins de lag) Ignore bad memory accesses = Ignorer les mauvais accès mémoire diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 5b8b4a0442..21d4f49ab8 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -1423,14 +1423,18 @@ Final processed image = Final processed image Firmware installation failed = Produciuse un erro ao instalar o firmware # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grella # AI translated Hide navigation bar = Ocultar a barra de navegación # AI translated I/O timing method = Método de sincronización de E/S +Icon size = Icon size Install or upgrade firmware from game discs = Instalar ou actualizar o firmware desde os discos de xogo # AI translated Installed firmware = Firmware instalado # AI translated Installing firmware = Instalando firmware # AI translated JIT using IR = JIT using IR Language = Idioma +Large list = Lista grande # AI translated Launch XMB = Iniciar o XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Carpeta de gardado en installed.txt @@ -1461,7 +1465,6 @@ Fast Memory = Memoria rápida (inestable) Force real clock sync (slower, less lag) = Forzar sinc. real de reloxo (lento, menos lag) Games list settings = Games list settings General = Xeral -Grid icon size = Grid icon size Help the PPSSPP team = Axuda ó equipo de PPSSPP Host (bugs, less lag) = Anfitrión (Erros, menos lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index bd811a8c70..dbdd4ecb70 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -1423,14 +1423,18 @@ Final processed image = Final processed image Firmware installation failed = Η εγκατάσταση του υλικολογισμικού απέτυχε # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Πλέγμα # AI translated Hide navigation bar = Απόκρυψη γραμμής πλοήγησης # AI translated I/O timing method = Μέθοδος χρονισμού I/O +Icon size = Icon size Install or upgrade firmware from game discs = Εγκατάσταση ή ενημέρωση υλικολογισμικού από δίσκους παιχνιδιών # AI translated Installed firmware = Το υλικολογισμικό εγκαταστάθηκε # AI translated Installing firmware = Εγκατάσταση υλικολογισμικού # AI translated JIT using IR = JIT using IR Language = Γλώσσα +Large list = Μεγάλη λίστα # AI translated Launch XMB = Εκκίνηση XMB # AI translated +List = Λίστα # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Αλλαγή φακέλου Memory Stick Memory Stick in installed.txt = Αποθήκευση διαδρομής στο installed.txt @@ -1461,7 +1465,6 @@ Fast Memory = Γρήγορη Μνήμη (ασταθής) Force real clock sync (slower, less lag) = Εξαναγκασμός συγχρονισμού πραγματικού χρόνου (πιο αργό αλλά λιγότερες καθυστερήσεις) Games list settings = Games list settings General = Γενικά -Grid icon size = Grid icon size Help the PPSSPP team = Βοηθήστε την ομάδα του PPSSPP Host (bugs, less lag) = Host (σφάλματα, λιγότερη καθυστέρηση) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index c16c3868fc..210762c41a 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -1418,10 +1418,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grid Hide navigation bar = להסתיר את סרגל הניווט # AI translated I/O timing method = I/O timing method +Icon size = Icon size JIT using IR = JIT using IR Language = שפה +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1452,7 +1456,6 @@ Fast Memory = עיבוד מהיר של זיכרון (לא יציב) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) Games list settings = Games list settings General = כללי -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index c130c3a915..ea9dd5bbb5 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -1417,10 +1417,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grid Hide navigation bar = טווינה לגרס תא ריתסהל # AI translated I/O timing method = I/O timing method +Icon size = Icon size JIT using IR = JIT using IR Language = הפש +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1451,7 +1455,6 @@ Fast Memory = )ביצי אל( ןורכיז לש ריהמ דוביע Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) Games list settings = Games list settings General = יללכ -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 56915dfb93..b054f2115c 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Instalacija firmvera nije uspjela # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Mreža # AI translated Hide navigation bar = Sakrij navigacijski trak # AI translated I/O timing method = I/O metoda timing-a +Icon size = Veličina ikona # AI translated Install or upgrade firmware from game discs = Instaliraj ili nadogradi firmver s diskova igara # AI translated Installed firmware = Firmver instaliran # AI translated Installing firmware = Instaliranje firmvera # AI translated JIT using IR = JIT using IR Language = Jezik +Large list = Veliki popis # AI translated Launch XMB = Pokreni XMB # AI translated +List = Popis # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Promijeni mapu Memorijskoga sticka Memory Stick in installed.txt = Spremi put u installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Brza memorija (nestabilno) Force real clock sync (slower, less lag) = Prisili pravo-satno sinkroniziranje (sporije, manje šteka) Games list settings = Games list settings General = Generalno -Grid icon size = Veličina ikona na mreži Help the PPSSPP team = Pomozite PPSSPP timu Host (bugs, less lag) = Domaći (bugovi, manje šteka) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index ae468e0ec7..9164737535 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = A firmware telepítése sikertelen # AI translated Floating symbols = Lebegő szimbólumok Game crashed = A játék összeomlott +Grid = Rács # AI translated Hide navigation bar = Navigációs sáv elrejtése # AI translated I/O timing method = I/O időzítési metódus +Icon size = Ikonok mérete # AI translated Install or upgrade firmware from game discs = Firmware telepítése vagy frissítése játéklemezekről # AI translated Installed firmware = Firmware telepítve # AI translated Installing firmware = Firmware telepítése # AI translated JIT using IR = JIT using IR Language = Nyelv +Large list = Nagy lista # AI translated Launch XMB = XMB indítása # AI translated +List = Lista # AI translated Loaded plugin: %1 = Betöltött bővítmény: %1 Memory Stick folder = Memóriakártya mappája Memory Stick in installed.txt = Memóriakártya helye az installed.txt-ben @@ -1462,7 +1466,6 @@ Fast Memory = Gyors memória elérés (instabil) Force real clock sync (slower, less lag) = Valós idejű óra szinkron kényszerítése (lassabb, kevesebb lag) Games list settings = Játéklista beállításai General = Általános -Grid icon size = Ikonok mérete rácsnézetben Help the PPSSPP team = Segítsd a PPSSPP csapatát Host (bugs, less lag) = Host (hibák, kevesebb lag) Ignore bad memory accesses = Hibás memóriaelérések figyelmen kívül hagyása diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index ef8309059c..5cc1c087dc 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -1424,14 +1424,18 @@ Final processed image = Gambar final yang terproses Firmware installation failed = Pemasangan firmware gagal # AI translated Floating symbols = Simbol mengambang Game crashed = Game Macet +Grid = Kisi # AI translated Hide navigation bar = Sembunyikan bilah navigasi # AI translated I/O timing method = Metode timing I/O +Icon size = Ukuran ikon # AI translated Install or upgrade firmware from game discs = Pasang atau perbarui firmware dari disk gim # AI translated Installed firmware = Firmware terpasang # AI translated Installing firmware = Memasang firmware # AI translated JIT using IR = JIT menggunakan IR Language = Bahasa +Large list = Daftar besar # AI translated Launch XMB = Jalankan XMB # AI translated +List = Daftar # AI translated Loaded plugin: %1 = Plugin dimuat: %1 Memory Stick folder = Berkas Memory Stick Memory Stick in installed.txt = Memory Stick dalam installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Memori cepat (tidak stabil) Force real clock sync (slower, less lag) = Paksa sinkronisasi pewaktu nyata (lambat, namun lebih tepat) Games list settings = Daftar pengaturan game General = Umum -Grid icon size = Ukuran ikon kisi Help the PPSSPP team = Bantu tim PPSSPP Host (bugs, less lag) = Inang (ada bug tapi lebih cepat) Ignore bad memory accesses = Abaikan akses memori yang buruk diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index a805397eec..c2e9accae9 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -1426,14 +1426,18 @@ Final processed image = Immagine finale elaborata Firmware installation failed = Installazione del firmware fallita # AI translated Floating symbols = Simboli fluttuanti Game crashed = Il gioco è andato in crash +Grid = Griglia # AI translated Hide navigation bar = Nascondi barra di navigazione # AI translated I/O timing method = Metodo di temporizzazione I/O +Icon size = Dimensioni delle icone Install or upgrade firmware from game discs = Installa o aggiorna il firmware dai dischi di gioco # AI translated Installed firmware = Firmware installato # AI translated Installing firmware = Installazione firmware # AI translated JIT using IR = JIT utilizzando IR Language = Lingua +Large list = Elenco grande # AI translated Launch XMB = Avvia l'XMB # AI translated +List = Elenco # AI translated Loaded plugin: %1 = Plugin caricato: %1 Memory Stick folder = Cartella della Memory Stick Memory Stick in installed.txt = Salva il percorso in "installed.txt" @@ -1490,7 +1494,6 @@ Transparent UI background = Sfondo trasparente dell'interfaccia UI = Interfaccia Games list settings = Impostazioni Lista giochi General = Generali -Grid icon size = Dimensioni delle icone Help the PPSSPP team = Aiuta il gruppo del PPSSPP Host (bugs, less lag) = Host (buggato, poca lag) Ignore bad memory accesses = Ignora i cattivi accessi alla memoria diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 327c45d4a9..8631f727ce 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1424,14 +1424,18 @@ Final processed image = 最後に処理された画像形式 Firmware installation failed = ファームウェアのインストールに失敗しました # AI translated Floating symbols = フローティングシンボル(○✕△□アイコン) Game crashed = ゲームがクラッシュしました +Grid = グリッド # AI translated Hide navigation bar = ナビゲーションバーを隠す # AI translated I/O timing method = 入出力のタイミング +Icon size = アイコンサイズ # AI translated Install or upgrade firmware from game discs = ゲームディスクからファームウェアをインストールまたはアップデート # AI translated Installed firmware = ファームウェアをインストールしました # AI translated Installing firmware = ファームウェアをインストール中 # AI translated JIT using IR = IRを使用したJIT Language = 言語 +Large list = 大きいリスト # AI translated Launch XMB = XMBを起動 # AI translated +List = リスト # AI translated Loaded plugin: %1 = 読み込まれたプラグイン: %1 Memory Stick folder = メモリースティックフォルダを変更する Memory Stick in installed.txt = パスを installed.txt に保存する @@ -1462,7 +1466,6 @@ Fast Memory = 高速メモリ (不安定) Force real clock sync (slower, less lag) = リアルクロックへの同期を強制する (低速化, ラグ減少) Games list settings = ゲームリストの設定 General = 全般 -Grid icon size = グリッド表示時のアイコンサイズ Help the PPSSPP team = PPSSPPチームを支援する Host (bugs, less lag) = ホスト (バグあり, ラグは少ない) Ignore bad memory accesses = 不正なメモリアクセスを無視する diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index e4ab90a3c2..b3ab7e21ad 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -1416,10 +1416,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grid Hide navigation bar = Sembunyikan bilah navigasi # AI translated I/O timing method = IO wektu method +Icon size = Icon size JIT using IR = JIT using IR Language = Basa +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Nyimpen path ing installed.txt @@ -1450,7 +1454,6 @@ Fast Memory = Memory cepet (ora stabil) Force real clock sync (slower, less lag) = Pasukan jam nyata sink (alon, kurang lag) Games list settings = Games list settings General = Umum -Grid icon size = Grid icon size Help the PPSSPP team = Bantu tim PPSSPP Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/km_KH.ini b/assets/lang/km_KH.ini index b6974a33f2..3885d692dd 100644 --- a/assets/lang/km_KH.ini +++ b/assets/lang/km_KH.ini @@ -1401,9 +1401,13 @@ Daylight savings =ការសន្សំពន្លឺថ្ងៃ Default tab =ផ្ទាំងលំនាំដើម Dynarec/JIT (recommended) =Dynarec/JIT (បានណែនាំ) Final processed image =រូបភាពដែលបានដំណើរការចុងក្រោយ +Grid = Grid Hide navigation bar =លាក់របាររុករក I/O timing method =វិធីសាស្ត្រកំណត់ពេលវេលា I/O +Icon size = ទំហំរូបតំណាង # AI translated JIT using IR =JIT ដោយប្រើ IR +Large list = Large list +List = List Loaded plugin: %1 =កម្មវិធីជំនួយដែលបានផ្ទុក៖ %1 Memory Stick folder =ថត Memory Stick Memory Stick in installed.txt =Memory Stick នៅក្នុង install.txt @@ -1439,7 +1443,6 @@ Force real clock sync (slower, less lag) =បង្ខំ​ឱ្យ​ធ្ Game crashed =ហ្គេមបានគាំង Games list settings =ការកំណត់បញ្ជីហ្គេម General =ទូទៅ -Grid icon size =ទំហំរូបតំណាងក្រឡាចត្រង្គ Help the PPSSPP team =ជួយក្រុម PPSSPP Host (bugs, less lag) =ម៉ាស៊ីន (កំហុស ភាពយឺតយ៉ាវតិច) Ignore bad memory accesses =មិនអើពើការចូលប្រើអង្គចងចាំមិនល្អ diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 4d89b68bac..c191ee6e61 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -1411,13 +1411,17 @@ Default tab = 기본 탭 Dynarec/JIT (recommended) = 동적 재컴파일/JIT (추천) Final processed image = 최종 처리된 이미지 Firmware installation failed = 펌웨어 설치 실패 # AI translated +Grid = 그리드 # AI translated Hide navigation bar = 탐색 모음 숨기기 # AI translated I/O timing method = I/O 타이밍 방식 +Icon size = 아이콘 크기 # AI translated Install or upgrade firmware from game discs = 게임 디스크에서 펌웨어 설치 또는 업그레이드 # AI translated Installed firmware = 펌웨어를 설치했습니다 # AI translated Installing firmware = 펌웨어 설치 중 # AI translated JIT using IR = IR을 이용한 JIT +Large list = 큰 목록 # AI translated Launch XMB = XMB 실행 # AI translated +List = 목록 # AI translated Loaded plugin: %1 = 로드된 플러그인: %1 Memory Stick folder = 메모리 스틱 폴더 Memory Stick in installed.txt = install.txt의 메모리 스틱 @@ -1453,7 +1457,6 @@ Force real clock sync (slower, less lag) = 실제 클럭 동기화 강제 실행 Game crashed = 게임 충돌 Games list settings = 게임 목록 설정 General = 일반 -Grid icon size = 그리드 아이콘 크기 Help the PPSSPP team = PPSSPP 팀 돕기 Host (bugs, less lag) = 호스트 (버그, 지연 감소) Ignore bad memory accesses = 잘못된 메모리 접속 무시 diff --git a/assets/lang/ku_SO.ini b/assets/lang/ku_SO.ini index 61e25088bf..980d55bac4 100644 --- a/assets/lang/ku_SO.ini +++ b/assets/lang/ku_SO.ini @@ -1418,9 +1418,13 @@ Default tab = Default tab Dynarec/JIT (recommended) = Dynarec/JIT (recommended) Enable plugins = Enable plugins Final processed image = Final processed image +Grid = Grid Hide navigation bar = Şopandina barê navegerê # AI translated I/O timing method = I/O timing method +Icon size = Icon size JIT using IR = JIT using IR +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = فۆڵدەری میمۆری Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1455,7 +1459,6 @@ Force real clock sync (slower, less lag) = Force real clock sync (slower, less l Game crashed = Game crashed Games list settings = سێتینگەکانی لیستی یاریەکان General = گشتی -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 939d5a303e..a147765c60 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -1416,10 +1416,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grid Hide navigation bar = ເຊື່ອນບານນິບນໍາ # AI translated I/O timing method = ທາງເລືອກຄຳນວນເວລາ ຮັບ/ສົ່ງ (I/O) +Icon size = Icon size JIT using IR = JIT using IR Language = ພາສາ +Large list = Large list +List = List Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = ບັນທຶກຂໍ້ມູນໃນ installed.txt @@ -1450,7 +1454,6 @@ Fast Memory = ໜ່ວຍຄວາມຈຳເຮັດວຽກໄວຂຶ້ Force real clock sync (slower, less lag) = ບັງຄັບການຊິງສັນຍານຄວາມຖີ່ (ຊ້າກວ່າ, ແລັກໜ້ອຍກວ່າ) Games list settings = Games list settings General = ທົ່ວໄປ -Grid icon size = Grid icon size Help the PPSSPP team = ຊ່ອຍເຫຼືອທີມງານ PPSSPP Host (bugs, less lag) = Host (ອາດມີບັ໊ກ, ແລັກໜ້ອຍລົງ) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index ea8230c10a..b0db152e28 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -1418,10 +1418,14 @@ Failed to load state for load undo. Error in the file system. = Failed to load s Final processed image = Final processed image Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Tinklelis # AI translated Hide navigation bar = Paslėpti navigacijos juostą # AI translated I/O timing method = I/O timing method +Icon size = Icon size JIT using IR = JIT using IR Language = Kalba +Large list = Didelis sąrašas # AI translated +List = Sąrašas # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1452,7 +1456,6 @@ Fast Memory = Greita atmintis (nestabili) Force real clock sync (slower, less lag) = Priversti tikro greičio sinchronizaciją (lėtesnis, mažiau striginėjimų) Games list settings = Games list settings General = Pagrindiniai -Grid icon size = Grid icon size Help the PPSSPP team = Help the PPSSPP team Host (bugs, less lag) = Host (bugs, less lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 278f6950e3..271e645a67 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -1424,14 +1424,18 @@ Final processed image = Imej pemprosesan akhir Firmware installation failed = Pemasangan firmware gagal # AI translated Floating symbols = Simbol terapung Game crashed = Permainan terhenti (crashed) +Grid = Grid # same as English Hide navigation bar = Sembunyikan bar navigasi I/O timing method = Kaedah penentuan masa I/O +Icon size = Saiz ikon # AI translated Install or upgrade firmware from game discs = Pasang atau kemas kini firmware dari cakera permainan # AI translated Installed firmware = Firmware dipasang # AI translated Installing firmware = Memasang firmware # AI translated JIT using IR = JIT menggunakan IR Language = Bahasa +Large list = Senarai besar # AI translated Launch XMB = Jalankan XMB # AI translated +List = Senarai # AI translated Loaded plugin: %1 = Pemalam dimuatkan: %1 Memory Stick folder = Folder Memory Stick Memory Stick in installed.txt = Memory Stick dalam installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Memori dilajukan (tidak stabil) Force real clock sync (slower, less lag) = Paksa penyelarasan masa sebenar (lebih perlahan, kurang selang masa) Games list settings = Tetapan senarai permainan General = Umum -Grid icon size = Saiz ikon grid Help the PPSSPP team = Bantu pasukan PPSSPP Host (bugs, less lag) = Perumah (pepijat, kurang selang masa) Ignore bad memory accesses = Abaikan akses memori yang rosak diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index c43dcc8dc1..eecc8cdebe 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Firmware-installatie mislukt # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Raster # AI translated Hide navigation bar = Verberg navigatiebalk # AI translated I/O timing method = I/O-timingmethode +Icon size = Icon size Install or upgrade firmware from game discs = Firmware installeren of bijwerken vanaf gamediscs # AI translated Installed firmware = Firmware geïnstalleerd # AI translated Installing firmware = Firmware installeren # AI translated JIT using IR = JIT using IR Language = Taal +Large list = Grote lijst # AI translated Launch XMB = XMB starten # AI translated +List = Lijst # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Opslagpad in installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Snel geheugen (instabiel) Force real clock sync (slower, less lag) = Kloksnelheid gelijkzetten (trager, minder lag) Games list settings = Games list settings General = Algemeen -Grid icon size = Grid icon size Help the PPSSPP team = Help het PPSSPP-team Host (bugs, less lag) = Host (bugs, minder lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/nn_NO.ini b/assets/lang/nn_NO.ini index f4768de507..3687d7eb2e 100644 --- a/assets/lang/nn_NO.ini +++ b/assets/lang/nn_NO.ini @@ -1436,13 +1436,17 @@ Default tab = Standardfane Dynarec/JIT (recommended) = Dynarec/JIT (tilrådd) Final processed image = Endeleg handsama bilete Firmware installation failed = Installasjonen av fastvara mislukkast # AI translated +Grid = Rutenett # AI translated Hide navigation bar = Skjul navigasjonslinja I/O timing method = Metode for I/U-timing +Icon size = Ikonstorleik # AI translated Install or upgrade firmware from game discs = Installer eller oppgrader fastvare frå spelplater # AI translated Installed firmware = Fastvare installert # AI translated Installing firmware = Installerer fastvare # AI translated JIT using IR = JIT med IR +Large list = Stor liste # AI translated Launch XMB = Start XMB # AI translated +List = Liste # AI translated Loaded plugin: %1 = Lasta inn programtillegg: %1 Memory Stick folder = Memory Stick-mappe Memory Stick in installed.txt = Memory Stick i installed.txt @@ -1478,7 +1482,6 @@ Force real clock sync (slower, less lag) = Tving ekte klokkesynk (tregare, mindr Game crashed = Spelet krasja Games list settings = Innstillingar for spelliste General = Generelt -Grid icon size = Ikonstorleik i rutenett Help the PPSSPP team = Hjelp PPSSPP-laget Host (bugs, less lag) = Vert (feil, mindre forseinking) Ignore bad memory accesses = Ignorer ugyldige minnetilgangar diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 07e7f60e96..fb9eaf67fa 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -1436,13 +1436,17 @@ Default tab = Standardfane Dynarec/JIT (recommended) = Dynarec/JIT (anbefales) Final processed image = Endelig behandlet bilde Firmware installation failed = Installasjonen av fastvaren mislyktes # AI translated +Grid = Rutenett # AI translated Hide navigation bar = Skjul navigasjonslinjen # AI translated I/O timing method = Metode for I/U-timing +Icon size = Ikonstørrelse # AI translated Install or upgrade firmware from game discs = Installer eller oppgrader fastvare fra spillplater # AI translated Installed firmware = Fastvare installert # AI translated Installing firmware = Installerer fastvare # AI translated JIT using IR = JIT med IR +Large list = Stor liste # AI translated Launch XMB = Start XMB # AI translated +List = Liste # AI translated Loaded plugin: %1 = Lastet inn programtillegg: %1 Memory Stick folder = Memory Stick-mappe Memory Stick in installed.txt = Memory Stick i installed.txt @@ -1478,7 +1482,6 @@ Force real clock sync (slower, less lag) = Tving ekte klokkesynk (tregere, mindr Game crashed = Spillet krasjet Games list settings = Spilliste-innstillinger General = Generelt -Grid icon size = Ikonstørrelse i rutenett Help the PPSSPP team = Hjelp PPSSPP-teamet Host (bugs, less lag) = Vert (feil, mindre forsinkelse) Ignore bad memory accesses = Ignorer ugyldige minnetilganger diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 0dd45ad570..863fb01bf3 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1432,13 +1432,17 @@ Final processed image = Obraz końcowy Firmware installation failed = Instalacja firmware'u nie powiodła się # AI translated Floating symbols = Przepływ symboli Game crashed = Gra uległa awarii +Grid = Siatka # AI translated Hide navigation bar = Ukryj pasek nawigacji # AI translated +Icon size = Rozmiar ikon # AI translated Install or upgrade firmware from game discs = Instaluj lub aktualizuj firmware z płyt z grami # AI translated Installed firmware = Zainstalowano firmware # AI translated Installing firmware = Instalowanie firmware'u # AI translated JIT using IR = JIT używając IR Language = Język +Large list = Duża lista # AI translated Launch XMB = Uruchom XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Załadowano wtyczek: %1 Memory Stick folder = Zmień folder Karty Pamięci Memory Stick in installed.txt = Ścieżka zapisu w installed.txt @@ -1469,7 +1473,6 @@ Fast Memory = Szybka pamięć (niestabilne) Force real clock sync (slower, less lag) = Wymuś rzeczywistą synchr. zegara (wolniej, mniej zacina) Games list settings = Ustawienia listy gier General = Ogólne -Grid icon size = Rozmiar siatki ikon Help the PPSSPP team = Pomóż zespołowi PPSSPP Host (bugs, less lag) = Host (błędy, mniejsze zacinanie) Ignore bad memory accesses = Ignoruj złe dostępy do pamięci diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 250f7d7139..84338d4046 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -1434,14 +1434,18 @@ Default tab = Aba padrão Dynarec/JIT (recommended) = Dynarec/JIT (recomendado) Final processed image = Imagem final processada Firmware installation failed = A instalação do firmware falhou +Grid = Grade # AI translated Hide navigation bar = Ocultar a barra de navegação Hide status bar = Esconder a barra de status I/O timing method = Método de cronometragem da E/S +Icon size = Tamanho dos ícones # AI translated Install or upgrade firmware from game discs = Instalar ou atualizar o firmware dos discos de jogos Installed firmware = Firmware instalado Installing firmware = Instalando firmware JIT using IR = JIT usando o IR +Large list = Lista grande # AI translated Launch XMB = Executar o XMB +List = Lista # AI translated Loaded plugin: %1 = Plugin carregado: %1 Memory Stick folder = Pasta do cartão de memória Memory Stick in installed.txt = Cartão de memória em installed.txt @@ -1477,7 +1481,6 @@ Force real clock sync (slower, less lag) = Forçar sincronização com o relógi Game crashed = O jogo teve um crash Games list settings = Configurações da lista de jogos General = Geral -Grid icon size = Tamanho do ícone da grade Help the PPSSPP team = Ajude o time do PPSSPP Host (bugs, less lag) = Hospedeiro (tem bugs, menos atrasos) Ignore bad memory accesses = Ignorar acessos ruins da memória diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index c1616f0122..a2fa6026b8 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -1436,13 +1436,17 @@ Default tab = Separador padrão Dynarec/JIT (recommended) = Dynarec / JIT (recomendado) Final processed image = Imagem final processada Firmware installation failed = Erro ao instalar o firmware # AI translated +Grid = Grade # AI translated Hide navigation bar = Esconder barra de navegação I/O timing method = Método de cronometragem de I/O +Icon size = Tamanho dos ícones # AI translated Install or upgrade firmware from game discs = Instalar ou atualizar o firmware a partir dos discos de jogo # AI translated Installed firmware = Firmware instalado # AI translated Installing firmware = A instalar firmware # AI translated JIT using IR = JIT com IR +Large list = Lista grande # AI translated Launch XMB = Iniciar o XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Plugin carregado: %1 Memory Stick folder = Diretório do cartão de memória Memory Stick in installed.txt = Diretório de salvamento em installed.txt @@ -1478,7 +1482,6 @@ Force real clock sync (slower, less lag) = Forçar sincronização com o relógi Game crashed = O jogo crashou :( Games list settings = Definições da lista de jogos General = Geral -Grid icon size = Tamanho do ícone da grade Help the PPSSPP team = Ajude a equipa da PPSSPP Host (bugs, less lag) = Hospedeiro (mais bugs, menos atrasos) Ignore bad memory accesses = Ignorar acessos inválidos à memória diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index e642970e82..7b3f8f71a1 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -1424,14 +1424,18 @@ Final processed image = Final processed image Firmware installation failed = Instalarea firmware-ului a eșuat # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Grilă # AI translated Hide navigation bar = Ascunde bara de navigare # AI translated I/O timing method = Metodă de temporizare I/O +Icon size = Icon size Install or upgrade firmware from game discs = Instalează sau actualizează firmware-ul de pe discurile de joc # AI translated Installed firmware = Firmware instalat # AI translated Installing firmware = Se instalează firmware-ul # AI translated JIT using IR = JIT using IR Language = Limbă +Large list = Listă mare # AI translated Launch XMB = Pornește XMB # AI translated +List = Listă # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1462,7 +1466,6 @@ Fast Memory = Memorie rapidă (instabil) Force real clock sync (slower, less lag) = Forțează sincronizare cu ceas real (lent, mai puțină latență) Games list settings = Games list settings General = General -Grid icon size = Grid icon size Help the PPSSPP team = Ajută echipa PPSSPP Host (bugs, less lag) = Host (cu erori, mai puțină latență) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index d9ff8fc518..c29c18ec29 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -1421,14 +1421,18 @@ Enable plugins = Включить плагины Final processed image = Окончательно обработанное изображение Firmware installation failed = Не удалось установить прошивку # AI translated Game crashed = Игра вылетела +Grid = Сетка # AI translated Hide navigation bar = Скрыть панель навигации I/O timing method = Метод тайминга ввода-вывода +Icon size = Размер ярлыков # AI translated Install or upgrade firmware from game discs = Устанавливать или обновлять прошивку с игровых дисков # AI translated Installed firmware = Прошивка установлена # AI translated Installing firmware = Установка прошивки # AI translated JIT using IR = JIT с использованием IR Language = Язык +Large list = Большой список # AI translated Launch XMB = Запустить XMB # AI translated +List = Список # AI translated Loaded plugin: %1 = Загружен плагин: %1 Memory Stick folder = Папка карты памяти Memory Stick in installed.txt = Карта памяти в файле installed.txt @@ -1462,7 +1466,6 @@ Floating symbols = Парящие символы Force real clock sync (slower, less lag) = Принудительная синхронизация реальной частоты ЦП (медленнее, меньше лагов) Games list settings = Настройки списка игр General = Основные -Grid icon size = Размер ярлыков в виде сетки Help the PPSSPP team = Помочь команде PPSSPP Host (bugs, less lag) = Хост (возможны баги, меньше лагов) Ignore bad memory accesses = Игнорировать ошибки доступа к памяти diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 0a7cecf510..81af97ccd8 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1426,14 +1426,18 @@ Final processed image = Slutgiltig bearbetad bild Firmware installation failed = Installationen av systemprogramvaran misslyckades # AI translated Floating symbols = Flytande symboler Game crashed = Spelet kraschade +Grid = Rutnät # AI translated Hide navigation bar = Dölj navigationsfältet Hide status bar = Dölj statusfältet I/O timing method = Metod för I/O-timing +Icon size = Ikonstorlek # AI translated Install or upgrade firmware from game discs = Installera eller uppgradera systemprogramvara från spelskivor # AI translated Installed firmware = Systemprogramvara installerad # AI translated Installing firmware = Installerar systemprogramvara # AI translated JIT using IR = JIT, med IR +Large list = Stor lista # AI translated Launch XMB = Starta XMB # AI translated +List = Lista # AI translated Loaded plugin: %1 = Laddad insticksmodul: %1 Memory Stick folder = Memory Stick-mapp Memory Stick in installed.txt = Memory Stick-mapp från installed.txt @@ -1464,7 +1468,6 @@ Fast Memory = Snabbt minne (instabilt) Force real clock sync (slower, less lag) = Tvinga synkronisering med realtidsklockan (långsammare, mindre fördröjning) Games list settings = Inställningar för spellistan General = Allmänt -Grid icon size = Ikonstorlek i rutnät Help the PPSSPP team = Stöd PPSSPP-teamet Host (bugs, less lag) = Värd (buggar, mindre lagg) Ignore bad memory accesses = Ignorera felaktiga minnesåtkomster diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index f58f11be07..128039e459 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -1420,10 +1420,14 @@ Failed to load state for load undo. Error in the file system. = Nabigong i-load Final processed image = Final processed image Floating symbols = Lumulutang na mga simbolo Game crashed = Na-crash ang laro +Grid = Grid # same as English Hide navigation bar = Пӯшида кардан бари муҳити навигатсионӣ # AI translated I/O timing method = I/O timing method +Icon size = Sukat ng Icon # AI translated JIT using IR = JIT gamit ang IR Language = Wika +Large list = Malaking listahan # AI translated +List = Listahan # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Folder ng Memory Stickd Memory Stick in installed.txt = I-save ang sinasabing 'path' sa installed.txt @@ -1454,7 +1458,6 @@ Fast Memory = Mabilis na memorya (hindi stable) Force real clock sync (slower, less lag) = Pilitin mag-sync sa 'real clock' (babagal pero mababawasan ang lag) Games list settings = Games list settings General = Pangkalahatan -Grid icon size = Sukat ng Grid Icon Help the PPSSPP team = Tumulong sa PPSSPP team Host (bugs, less lag) = Host (magkakaroon ng bug pero mababawasan ang lag) Ignore bad memory accesses = Baliwalain ang bad memory accesses diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 933c961770..d979a3c9b0 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -1490,11 +1490,12 @@ Force real clock sync (slower, less lag) = บังคับการซิง Game crashed = Game crashed Games list settings = การตั้งค่าในรายการเกม General = ทั่วไป -Grid icon size = ขนาดของไอคอนเกม +Grid = ตาราง # AI translated Help the PPSSPP team = ช่วยเหลือทีมงาน PPSSPP Hide navigation bar = ซ่อนแถบการนำทาง Host (bugs, less lag) = โฮสต์ (อาจเกิดบั๊ก, แล็กน้อยลง) I/O timing method = ทางเลือกคำนวณเวลา รับ/ส่ง ข้อมูล +Icon size = ขนาดของไอคอนเกม Ignore bad memory accesses = ละเว้นการเข้าถึงหน่วยความจำที่ผิดพลาด Increase size = เพิ่มขนาดไอคอน Install or upgrade firmware from game discs = ติดตั้งหรืออัปเกรดเฟิร์มแวร์จากแผ่นเกม # AI translated @@ -1504,7 +1505,9 @@ Interpreter = อินเตอร์พรีเตอร์ IR Interpreter = IR อินเตอร์พรีเตอร์ JIT using IR = JIT ใช้งาน IR Language = ภาษา +Large list = รายการขนาดใหญ่ # AI translated Launch XMB = เปิด XMB # AI translated +List = รายการ # AI translated Loaded plugin: %1 = ปลั๊กอินถูกโหลดใช้แล้ว: %1 Memory Stick folder = เปลี่ยนแหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) Memory Stick Folder = โฟลเดอร์แหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index f4b9eb737e..dd5e74c62b 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1425,14 +1425,18 @@ Final processed image = Son işlenmiş görüntü Firmware installation failed = Yazılım kurulumu başarısız # AI translated Floating symbols = Kayan Simgeler Game crashed = Oyun çöktü +Grid = Izgara # AI translated Hide navigation bar = Gezinti çubuğunu gizle # AI translated I/O timing method = IO Zamanlama Yöntemi +Icon size = Simge boyutu # AI translated Install or upgrade firmware from game discs = Oyun disklerinden yazılımı kur veya yükselt # AI translated Installed firmware = Yazılım kuruldu # AI translated Installing firmware = Yazılım kuruluyor # AI translated JIT using IR = IR kullanarak JIT Language = Dil +Large list = Büyük liste # AI translated Launch XMB = XMB'yi başlat # AI translated +List = Liste # AI translated Loaded plugin: %1 = Yüklenen eklenti: %1 Memory Stick folder = Hafıza Kartı Klasörü Memory Stick in installed.txt = Hafıza Kartını installed.txt Üstüne Kaydet @@ -1463,7 +1467,6 @@ Fast Memory = Hızlı Bellek Force real clock sync (slower, less lag) = Gerçek Saat Hızına Eşitlemeye Zorla (yavaş, az gecikme) Games list settings = Oyun Listesi Ayarları General = Genel -Grid icon size = Izgara simge boyutu Help the PPSSPP team = PPSSPP Takımına Yardım Et Host (bugs, less lag) = Ana makine (hatalı, az gecikme) Ignore bad memory accesses = Kötü Bellek Erişimlerini Yoksay diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index c79a4fc62f..bf0950d0be 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -1423,14 +1423,18 @@ Final processed image = Остаточне оброблене зображенн Firmware installation failed = Не вдалося встановити прошивку # AI translated Floating symbols = Пари символи Game crashed = Гра вийшла з ладу +Grid = Сітка # AI translated Hide navigation bar = Сховати панель навігації # AI translated I/O timing method = Метод таймінгу введення-виведення +Icon size = Розмір піктограм # AI translated Install or upgrade firmware from game discs = Встановлювати або оновлювати прошивку з ігрових дисків # AI translated Installed firmware = Прошивку встановлено # AI translated Installing firmware = Встановлення прошивки # AI translated JIT using IR = JIT використовуючи IR Language = Мова +Large list = Великий список # AI translated Launch XMB = Запустити XMB # AI translated +List = Список # AI translated Loaded plugin: %1 = Завантажений плагін: %1 Memory Stick folder = Змінити папку для карти пам'яті Memory Stick in installed.txt = Шлях до збережень в installed.txt @@ -1461,7 +1465,6 @@ Fast Memory = Швидка пам'ять (нестабільно) Force real clock sync (slower, less lag) = Примусова синхронізація реальної частоти ЦП (повільніше, можливі лаги) Games list settings = Налаштування списку ігор General = Загальні -Grid icon size = Розмір піктограми сітки Help the PPSSPP team = Допомога Команді PPSSPP Host (bugs, less lag) = Хост (повільніше, можливі лаги) Ignore bad memory accesses = Ігноруйте погані звернення до пам'яті diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 46fd5eba29..805d1bd1ab 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -1423,14 +1423,18 @@ Final processed image = Final processed image Firmware installation failed = Cài đặt firmware thất bại # AI translated Floating symbols = Floating symbols Game crashed = Game crashed +Grid = Lưới # AI translated Hide navigation bar = Ẩn thanh điều hướng # AI translated I/O timing method = I/O phương pháp thời gian +Icon size = Icon size Install or upgrade firmware from game discs = Cài đặt hoặc nâng cấp firmware từ đĩa game # AI translated Installed firmware = Đã cài đặt firmware # AI translated Installing firmware = Đang cài đặt firmware # AI translated JIT using IR = JIT using IR Language = Ngôn ngữ +Large list = Danh sách lớn # AI translated Launch XMB = Khởi chạy XMB # AI translated +List = Danh sách # AI translated Loaded plugin: %1 = Loaded plugin: %1 Memory Stick folder = Memory Stick folder Memory Stick in installed.txt = Memory Stick in installed.txt @@ -1461,7 +1465,6 @@ Fast Memory = Bộ nhớ nhanh (không ổn định) Force real clock sync (slower, less lag) = Buộc đồng bộ tốc độ xung nhịp (chậm hơn, giảm lag hơn) Games list settings = Games list settings General = Linh tinh -Grid icon size = Grid icon size Help the PPSSPP team = Giúp nhóm PPSSPP Host (bugs, less lag) = Host (lỗi, ít lag) Ignore bad memory accesses = Ignore bad memory accesses diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index d2b667410e..739b4cc8d3 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1413,13 +1413,17 @@ Dynarec/JIT (recommended) = 动态重编译 (推荐) Enable plugins = 启用插件 Final processed image = 实际输出图像 Firmware installation failed = 固件安装失败 # AI translated +Grid = 网格 # AI translated Hide navigation bar = 隐藏小白条 I/O timing method = I/O时序方法 +Icon size = 图标尺寸 # AI translated Install or upgrade firmware from game discs = 从游戏光盘安装或升级固件 # AI translated Installed firmware = 固件已安装 # AI translated Installing firmware = 正在安装固件 # AI translated JIT using IR = 动态重编译 (IR模式) +Large list = 大列表 # AI translated Launch XMB = 启动 XMB # AI translated +List = 列表 # AI translated Loaded plugin: %1 = 已加载插件: %1 Memory Stick in installed.txt = 记忆棒目录使用“installed.txt” Memory Stick in My Documents = 记忆棒目录使用“我的文档” @@ -1467,7 +1471,6 @@ Fast Memory = 快速内存 (不稳定) Force real clock sync (slower, less lag) = 强制同步实际时钟 (减少延迟,并降低性能) Games list settings = 游戏列表设置 General = 常规设置 -Grid icon size = 图标方格尺寸 Help the PPSSPP team = 帮助PPSSPP作者 Host (bugs, less lag) = 主机模式 (存在错误, 不易卡顿) Ignore bad memory accesses = 忽略错误内存访问 (减少崩溃) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index d32024c1fc..42ddf927e1 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1413,14 +1413,18 @@ Enable plugins = 啟用外掛程式 Final processed image = 處理後影像 Firmware installation failed = 韌體安裝失敗 # AI translated Game crashed = 遊戲已當機 +Grid = 格狀 # AI translated Hide navigation bar = 隱藏導航欄 # AI translated I/O timing method = I/O 計時方法 +Icon size = 圖示大小 # AI translated Install or upgrade firmware from game discs = 從遊戲光碟安裝或升級韌體 # AI translated Installed firmware = 韌體已安裝 # AI translated Installing firmware = 正在安裝韌體 # AI translated JIT using IR = JIT 使用 IR Language = 語言 +Large list = 大型清單 # AI translated Launch XMB = 啟動 XMB # AI translated +List = 清單 # AI translated Loaded plugin: %1 = 載入的外掛程式: %1 Memory Stick folder = 記憶棒資料夾 Memory Stick in installed.txt = 儲存路徑於 installed.txt @@ -1454,7 +1458,6 @@ Floating symbols = 浮動符號 Force real clock sync (slower, less lag) = 強制真實時脈同步 (更慢,減少延遲) Games list settings = 遊戲清單設定 General = 一般 -Grid icon size = 格狀圖示大小 Help the PPSSPP team = 協助 PPSSPP 團隊 Host (bugs, less lag) = 主機 (更多錯誤,減少延遲) Ignore bad memory accesses = 忽略損毀的記憶體存取 From ef72f27fea4f9dc1fcb4cee7a35bd59dbd12211d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 11:00:00 +0200 Subject: [PATCH 5/8] Game browser: Keep the search and focus when returning from a game FocusGame cleared the path to focus right after setting it, so since the refresh became deferred nothing got refocused. The refresh also showed every game again while the search bar still showed the filter. Now an existing button is focused directly, without a refresh, and a refresh reapplies an active search filter. Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/GameBrowser.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index 5e6d9a602f..b7a5c00cc0 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -742,9 +742,19 @@ GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, b } void GameBrowser::FocusGame(const Path &gamePath) { + // If the button's still there, just focus it. That keeps the search results and scroll position. + if (gameList_) { + for (int i = 0; i < gameList_->GetNumSubviews(); i++) { + GameButton *button = dynamic_cast(gameList_->GetViewByIndex(i)); + if (button && button->GamePath() == gamePath && button->GetVisibility() == UI::V_VISIBLE) { + button->SetFocus(UI::FocusFlags::CAUSE_RESTORE); + return; + } + } + } + // Otherwise, Refresh focuses it when it recreates the buttons. focusGamePath_ = gamePath; refreshPending_ = true; - focusGamePath_.clear(); } void GameBrowser::SetPath(const Path &path) { @@ -1143,6 +1153,7 @@ void GameBrowser::Refresh() { b->SetFocus(FocusFlags::CAUSE_RESTORE); } } + focusGamePath_.clear(); // Show a button to toggle pinning at the very end. if ((browseFlags_ & BrowseFlags::PIN) && !path_.GetPath().empty()) { @@ -1163,6 +1174,11 @@ void GameBrowser::Refresh() { Add(new Spacer()); Add(new Choice(lastText_, ImageID("I_LINK_OUT"), new UI::LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT, Margins(10, 0, 0, 10))))->OnClick.Handle(this, &GameBrowser::LastClick); } + + // The new buttons are all visible, so filter them again if a search is active. + if (!search_.searchFilter.empty()) { + search_.ApplySearchFilter(gameList_, false); + } } bool GameBrowser::IsCurrentPathPinned() { From ce8f48980acbb50a8d2caa9a4089959c47d34a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 11:00:00 +0200 Subject: [PATCH 6/8] Game browser: Default to the large list for Games and Homebrew, bigger folders The old GridView keys are now read as ints, so a missing key can be told apart from false. Configs without them get the new defaults, while existing ones still migrate their choice. Folders get taller lines in the large list too, though not as tall as the games. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/Config.cpp | 32 ++++++++++++++++++++++---------- Core/Config.h | 10 +++++----- UI/GameBrowser.cpp | 26 +++++++++++++++++--------- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 17dd44d34a..d33e9f49de 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -195,14 +195,26 @@ static bool DefaultEnableStateUndo() { return true; } -static int GameBrowserViewFromGridView(bool gridView) { - return (int)(gridView ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST); +// The old GridView bools, read as ints so a missing key (-1) can be told apart from false. +static int LegacyGridViewFromString(const std::string &value) { + return equalsNoCase(value, "True") ? 1 : 0; } -static int DefaultGameBrowserView1() { return GameBrowserViewFromGridView(g_Config.bGridView1); } -static int DefaultGameBrowserView2() { return GameBrowserViewFromGridView(g_Config.bGridView2); } -static int DefaultGameBrowserView3() { return GameBrowserViewFromGridView(g_Config.bGridView3); } -static int DefaultGameBrowserView4() { return GameBrowserViewFromGridView(g_Config.bGridView4); } +static std::string LegacyGridViewToString(int value) { + return value == 1 ? "True" : "False"; +} + +static int GameBrowserViewFromGridView(int legacyGridView, GameBrowserViewMode defaultMode) { + if (legacyGridView < 0) { + return (int)defaultMode; + } + return (int)(legacyGridView ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST); +} + +static int DefaultGameBrowserView1() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView1, GameBrowserViewMode::GRID); } +static int DefaultGameBrowserView2() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView2, GameBrowserViewMode::LARGE_LIST); } +static int DefaultGameBrowserView3() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView3, GameBrowserViewMode::LARGE_LIST); } +static int DefaultGameBrowserView4() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView4, GameBrowserViewMode::LIST); } static float DefaultGameGridScale() { #if PPSSPP_PLATFORM(IOS) @@ -292,10 +304,10 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("ShowRegionOnGameIcon", SETTING(g_Config, bShowRegionOnGameIcon), false, CfgFlag::DEFAULT), ConfigSetting("ShowIDOnGameIcon", SETTING(g_Config, bShowIDOnGameIcon), false, CfgFlag::DEFAULT), ConfigSetting("GameGridScale", SETTING(g_Config, fGameGridScale), &DefaultGameGridScale, CfgFlag::DEFAULT), - ConfigSetting("GridView1", SETTING(g_Config, bGridView1), true, CfgFlag::DONT_SAVE), - ConfigSetting("GridView2", SETTING(g_Config, bGridView2), true, CfgFlag::DONT_SAVE), - ConfigSetting("GridView3", SETTING(g_Config, bGridView3), false, CfgFlag::DONT_SAVE), - ConfigSetting("GridView4", SETTING(g_Config, bGridView4), false, CfgFlag::DONT_SAVE), + ConfigSetting("GridView1", SETTING(g_Config, iLegacyGridView1), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), + ConfigSetting("GridView2", SETTING(g_Config, iLegacyGridView2), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), + ConfigSetting("GridView3", SETTING(g_Config, iLegacyGridView3), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), + ConfigSetting("GridView4", SETTING(g_Config, iLegacyGridView4), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), // These must come after GridView*, which their defaults are taken from. ConfigSetting("GameBrowserView1", SETTING(g_Config, iGameBrowserView1), &DefaultGameBrowserView1, CfgFlag::DEFAULT), ConfigSetting("GameBrowserView2", SETTING(g_Config, iGameBrowserView2), &DefaultGameBrowserView2, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index d472373c15..41831ba759 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -473,11 +473,11 @@ public: int iGameBrowserView2; int iGameBrowserView3; int iGameBrowserView4; - // Only read, to migrate to iGameBrowserView*. - bool bGridView1; - bool bGridView2; - bool bGridView3; - bool bGridView4; + // The old GridView bools, only read, to migrate to iGameBrowserView*. -1 if missing. + int iLegacyGridView1; + int iLegacyGridView2; + int iLegacyGridView3; + int iLegacyGridView4; // Right analog binding int iRightAnalogUp; diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index b7a5c00cc0..ac58ebdb5b 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -56,6 +56,8 @@ static constexpr float LARGE_LIST_ICON_H = 80.0f; static constexpr float LARGE_LIST_PAD = 6.0f; static constexpr float LARGE_LIST_LEFT_PAD = 11.0f; static constexpr float LARGE_LIST_INFO_SIZE = 64.0f; +// Folders get bigger lines too, though not as big as the games. +static constexpr float LARGE_LIST_FOLDER_H = 50.0f; // Where the text starts in the list modes. static float ListTextX(GameBrowserViewMode viewMode) { @@ -671,12 +673,18 @@ std::string GameButton::DescribeText() const { class DirButton : public UI::Button { public: - DirButton(const Path &path, bool gridStyle, UI::LayoutParams *layoutParams) - : UI::Button(path.ToString(), layoutParams), path_(path), gridStyle_(gridStyle), absolute_(false) {} - DirButton(const Path &path, const std::string &text, bool gridStyle, UI::LayoutParams *layoutParams = 0) - : UI::Button(text, layoutParams), path_(path), gridStyle_(gridStyle), absolute_(true) {} + DirButton(const Path &path, GameBrowserViewMode viewMode, UI::LayoutParams *layoutParams) + : UI::Button(path.ToString(), layoutParams), path_(path), viewMode_(viewMode), absolute_(false) {} + DirButton(const Path &path, const std::string &text, GameBrowserViewMode viewMode, UI::LayoutParams *layoutParams = 0) + : UI::Button(text, layoutParams), path_(path), viewMode_(viewMode), absolute_(true) {} void Draw(UIContext &dc) override; + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { + UI::Button::GetContentDimensions(dc, w, h); + if (viewMode_ == GameBrowserViewMode::LARGE_LIST) { + h = std::max(h, LARGE_LIST_FOLDER_H * g_Config.fGameGridScale + LARGE_LIST_PAD * 2); + } + } const Path &GetPath() const { return path_; @@ -696,7 +704,7 @@ public: private: Path path_; - bool gridStyle_; + GameBrowserViewMode viewMode_; bool absolute_; bool pinned_ = false; }; @@ -718,7 +726,7 @@ void DirButton::Draw(UIContext &dc) { if (!IsEnabled()) style = dc.GetTheme().itemDisabledStyle; dc.FillRect(style.background, bounds_); - DrawIconWithText(dc, image, text, bounds_, gridStyle_ ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST, style); + DrawIconWithText(dc, image, text, bounds_, viewMode_, style); } GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, int *viewMode, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams) @@ -1095,7 +1103,7 @@ void GameBrowser::Refresh() { if (!isGame && !isSaveData) { if (browseFlags_ & BrowseFlags::NAVIGATE) { - dirButtons.push_back(new DirButton(fileInfo[i].fullName, fileInfo[i].name, gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); + dirButtons.push_back(new DirButton(fileInfo[i].fullName, fileInfo[i].name, lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); } } else { gameButtons.push_back(new GameButton(fileInfo[i].fullName, lastViewMode_, new UI::LinearLayoutParams(gridStyle ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); @@ -1122,14 +1130,14 @@ void GameBrowser::Refresh() { if (browseFlags_ & BrowseFlags::NAVIGATE) { if (path_.CanNavigateUp()) { - gameList_->Add(new DirButton(Path(".."), gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> + gameList_->Add(new DirButton(Path(".."), lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))-> OnClick.Handle(this, &GameBrowser::NavigateClick); } // Add any pinned paths before other directories. auto pinnedPaths = GetPinnedPaths(); for (const auto &pinnedPath : pinnedPaths) { - DirButton *pinnedDir = gameList_->Add(new DirButton(pinnedPath, pinnedPath.GetFilename(), gridStyle, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); + DirButton *pinnedDir = gameList_->Add(new DirButton(pinnedPath, pinnedPath.GetFilename(), lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); pinnedDir->OnClick.Handle(this, &GameBrowser::NavigateClick); pinnedDir->SetPinned(true); } From 754e49c6d65e723781bb9c466b27ecd163e4a759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 11:12:00 +0200 Subject: [PATCH 7/8] Game browser: Switch existing installs to the large list on Games and Homebrew Their old grid setting is no longer migrated, so everyone gets the new view there. Recent and Remote still keep theirs. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/Config.cpp | 7 +++---- Core/Config.h | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index d33e9f49de..5ed393f27b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -211,9 +211,10 @@ static int GameBrowserViewFromGridView(int legacyGridView, GameBrowserViewMode d return (int)(legacyGridView ? GameBrowserViewMode::GRID : GameBrowserViewMode::LIST); } +// Games and Homebrew switch everyone to the large list, ignoring the old setting. The others keep it. static int DefaultGameBrowserView1() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView1, GameBrowserViewMode::GRID); } -static int DefaultGameBrowserView2() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView2, GameBrowserViewMode::LARGE_LIST); } -static int DefaultGameBrowserView3() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView3, GameBrowserViewMode::LARGE_LIST); } +static int DefaultGameBrowserView2() { return (int)GameBrowserViewMode::LARGE_LIST; } +static int DefaultGameBrowserView3() { return (int)GameBrowserViewMode::LARGE_LIST; } static int DefaultGameBrowserView4() { return GameBrowserViewFromGridView(g_Config.iLegacyGridView4, GameBrowserViewMode::LIST); } static float DefaultGameGridScale() { @@ -305,8 +306,6 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("ShowIDOnGameIcon", SETTING(g_Config, bShowIDOnGameIcon), false, CfgFlag::DEFAULT), ConfigSetting("GameGridScale", SETTING(g_Config, fGameGridScale), &DefaultGameGridScale, CfgFlag::DEFAULT), ConfigSetting("GridView1", SETTING(g_Config, iLegacyGridView1), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), - ConfigSetting("GridView2", SETTING(g_Config, iLegacyGridView2), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), - ConfigSetting("GridView3", SETTING(g_Config, iLegacyGridView3), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), ConfigSetting("GridView4", SETTING(g_Config, iLegacyGridView4), -1, &LegacyGridViewToString, &LegacyGridViewFromString, CfgFlag::DONT_SAVE), // These must come after GridView*, which their defaults are taken from. ConfigSetting("GameBrowserView1", SETTING(g_Config, iGameBrowserView1), &DefaultGameBrowserView1, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index 41831ba759..9c7ce903be 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -475,8 +475,6 @@ public: int iGameBrowserView4; // The old GridView bools, only read, to migrate to iGameBrowserView*. -1 if missing. int iLegacyGridView1; - int iLegacyGridView2; - int iLegacyGridView3; int iLegacyGridView4; // Right analog binding From 753e869ca1f81342debf5d8eebd82e80de29ef62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Oct 2026 11:17:44 +0200 Subject: [PATCH 8/8] Search: Drop the focus from a view the filter hides When a search stopped matching the focused game, it stayed focused while hidden, so its background and music kept going. Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/MiscViews.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/UI/MiscViews.cpp b/UI/MiscViews.cpp index 57eacf7134..c40cd938d5 100644 --- a/UI/MiscViews.cpp +++ b/UI/MiscViews.cpp @@ -434,11 +434,17 @@ void ViewSearch::ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFoc } } - if (firstMatch) { - if (setKeyboardFocus) { - UI::EnableFocusMovement(true); - UI::SetFocusedView(firstMatch, UI::FocusFlags::CAUSE_OTHER); - } + if (firstMatch && setKeyboardFocus) { + UI::EnableFocusMovement(true); + UI::SetFocusedView(firstMatch, UI::FocusFlags::CAUSE_OTHER); + return; + } + + // Don't leave the focus on a view we just hid. A game would keep showing its background and + // playing its music, for one. + UI::View *focused = UI::GetFocusedView(); + if (focused && focused->GetVisibility() == UI::V_GONE && viewGroup->ContainsSubview(focused)) { + UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_FOCUS_MOVE); } }