Files
ppsspp/UI/SavedataScreen.h
T
Henrik RydgårdandClaude Opus 5.5 b91bd6af86 Settings: Build the settings screen from pages described as data
Each tab is now a SettingsPage: a list of items (headers, settings, buttons,
hints, links to other pages) that a function builds and views are created
from. Settings are added with page->Setting(&g_Config.x), which takes
the label, the kind of view, the range or choices, units, labels for special
values and the default from the config. The pages keep what depends on the
UI (which settings to show and when, enable rules, and behavior that needs the
screen), and reach the screen through the page's SettingsPageHost.

A page can link to other pages, which open on top of it in the same tab,
under a bar showing where you are, like Tools > Developer tools > Graphics,
where the earlier pages can be clicked to go back to them. The bar has back,
search and help buttons, and the back key also goes back a page (or out of a
search) before leaving the screen. Each page remembers its scroll position.
In portrait there's no tab strip: a page links to the tabs, and the bar shows
just the current page's title. Rotating keeps showing the same page. Moving
between pages only focuses an item when navigating with a keyboard or
controller.

The developer tools are now pages linked from the Tools tab, instead of a
screen of their own. The in-game developer menu and
--start-screen=developertools open the settings on that page. The toggles of
live state (the remote debugger and the MIPS tracer) show and change it
through functions, and pretending to be in-game for the notification tests is
a flag on the OSD. The memory map and memstick tests, only reachable from
commented-out code, are removed.

Search lists the matching settings from all tabs and the pages they link to,
grouped by where they are. Each result goes to the setting on its page,
scrolled to and highlighted (outlined, when picked with a mouse or touch), or
for a page, opens it. This replaces the search tab and the old filter that
hid the views that didn't match, and with them ShowSearchControls. Changing
tabs leaves the search.

The pages, the bar and search are in SettingsPagesDialogScreen, between the
tabbed dialog screen and the settings screen, so the other tabbed screens
keep plain tabs.

Other visible changes:
- Reset buttons that went to the wrong value now go to the real default: the
  touch control auto-hide delay (was 20 seconds instead of 8), the mouse
  wheel delay (1 ms, below its own range, instead of 80) and the UI size (0
  instead of -1 on desktop). The alternative speeds get a reset button.
- Units are shown on more sliders (frames, MHz, seconds, Hz), and popups no
  longer spell out what 0 means in the units, since the zero label does.
  Units of up to three characters (%, x, ms, MHz) aren't translated.
- The Android HW scaler hides the scales the display is too small for,
  instead of cutting the list short.
- Choices are translated in the setting's own section.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 15:26:58 +01:00

175 lines
5.0 KiB
C++

// Copyright (c) 2015- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <functional>
#include <string>
#include "Common/File/Path.h"
#include "Common/UI/UIScreen.h"
#include "Common/UI/View.h"
#include "Common/UI/ViewGroup.h"
#include "UI/BaseScreens.h"
#include "UI/GameInfoCache.h"
#include "UI/TabbedDialogScreen.h"
enum class SavedataSortOption {
FILENAME,
SIZE,
DATE,
};
class SavedataBrowser : public UI::LinearLayout {
public:
SavedataBrowser(const Path &path, UI::LayoutParams *layoutParams = 0);
void Update() override;
void SetSortOption(SavedataSortOption opt);
void SetSearchFilter(const std::string &filter);
UI::Event OnChoice;
private:
static void PrepFilename(UI::View *);
static void PrepSize(UI::View *);
static void PrepDate(UI::View *);
static bool ByFilename(const UI::View *, const UI::View *);
static bool BySize(const UI::View *, const UI::View *);
static bool ByDate(const UI::View *, const UI::View *);
void Refresh();
void SavedataButtonClick(UI::EventParams &e);
SavedataSortOption sortOption_ = SavedataSortOption::FILENAME;
UI::ViewGroup *gameList_ = nullptr;
UI::TextView *noMatchView_ = nullptr;
UI::TextView *searchingView_ = nullptr;
Path path_;
std::string searchFilter_;
bool searchPending_ = false;
};
class SavedataView;
class SavedataPopupScreen : public UI::PopupScreen {
public:
SavedataPopupScreen(Path gamePath, Path savePath, std::string_view title);
const char *tag() const override { return "SavedataPopup"; }
void update() override;
void CreatePopupContents(UI::ViewGroup *parent) override;
protected:
UI::Size PopupWidth() const override { return 600; }
private:
SavedataView *savedataView_ = nullptr;
Path savePath_;
Path gamePath_;
};
class SavedataScreen : public UITabbedBaseDialogScreen {
public:
// gamePath can be empty, in that case this screen will show all savedata in the save directory.
SavedataScreen(const Path &gamePath) : UITabbedBaseDialogScreen(gamePath) {}
~SavedataScreen();
void dialogFinished(const Screen *dialog, DialogResult result) override;
void sendMessage(UIMessage message, const char *value) override;
ViewLayoutMode LayoutMode() const override {
return ViewLayoutMode::ApplyInsets;
}
const char *tag() const override { return "Savedata"; }
protected:
void CreateTabs() override;
void CreateExtraButtons(UI::ViewGroup *verticalLayout, int margins) override;
private:
void OnSavedataButtonClick(UI::EventParams &e);
void OnSearch(UI::EventParams &e);
void CreateSavedataTab(UI::ViewGroup *savedata);
void CreateSavestateTab(UI::ViewGroup *savestate);
SavedataSortOption sortOption_ = SavedataSortOption::FILENAME;
SavedataBrowser *dataBrowser_ = nullptr;
SavedataBrowser *stateBrowser_ = nullptr;
std::string searchFilter_;
};
class SavedataButton : public UI::Clickable {
public:
SavedataButton(const Path &gamePath, UI::LayoutParams *layoutParams = 0)
: UI::Clickable(layoutParams), savePath_(gamePath) {
SetTag(gamePath.ToString());
}
void Draw(UIContext &dc) override;
bool UpdateText();
std::string DescribeText() const override;
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override {
w = 500;
h = 74;
}
const Path &GamePath() const { return savePath_; }
uint64_t GetTotalSize() const {
return totalSize_;
}
int64_t GetDateSeconds() const {
return dateSeconds_;
}
void UpdateTotalSize();
void UpdateDateSeconds();
private:
void UpdateText(const std::shared_ptr<GameInfo> &ginfo);
Path savePath_;
std::string title_;
std::string subtitle_;
uint64_t totalSize_ = 0;
int64_t dateSeconds_ = 0;
bool hasTotalSize_ = false;
bool hasDateSeconds_ = false;
};
// View used for the detailed popup, and also in the import savedata comparison.
// It doesn't do its own data loading for that reason.
class SavedataView : public UI::LinearLayout {
public:
SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType type, bool showIcon, UI::LayoutParams *layoutParams = nullptr);
SavedataView(UIContext &dc, const Path &savePath, IdentifiedFileType type, std::string_view title, std::string_view savedataTitle, std::string_view savedataDetail, std::string_view fileSize, std::string_view mtime, bool showIcon, UI::LayoutParams *layoutParams = nullptr);
void UpdateGame(GameInfo *ginfo);
private:
UI::TextView *savedataTitle_ = nullptr;
UI::TextView *detail_ = nullptr;
UI::TextView *mTime_ = nullptr;
UI::TextView *fileSize_ = nullptr;
};