Misc UI and cmdline parse work

This commit is contained in:
Henrik Rydgård committed 2026-11-04 17:58:18 +01:00
1 parent 7b2860ec42
commit 9e78ef5677
12 files changed
+109 -57

No files matched your search

+13
View File
@@ -174,3 +174,16 @@ bool HitAnyAsserts() {
void ResetHitAnyAsserts() {
hitAnyAsserts = false;
}
void ShowMessageDialog(const char *title, const char *message, bool isError) {
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
const int msgBoxStyle = MB_ICONINFORMATION | MB_OK;
std::string text = message;
const char *caption = title;
std::wstring wcaption = ConvertUTF8ToWString(std::string(caption));
MessageBox(g_dialogParent, ConvertUTF8ToWString(text).c_str(), wcaption.c_str(), msgBoxStyle);
#else
// Just printf.
fprintf(stderr, "%s: %s\n", title, message);
#endif
}
+1
View File
@@ -154,6 +154,7 @@ void SetAssertCancelCallback(AssertNoCallbackFunc callback, void *userdata);
void SetCleanExitOnAssert();
void BreakIntoPSPDebugger(const char *reason = "(userbreak)");
void SetAssertDialogParent(void *handle); // HWND on windows. Ignored on other platforms.
void ShowMessageDialog(const char *title, const char *message, bool isError = false);
#if defined(__ANDROID__)
// Tricky macro to get the basename, that also works if *built* on Win32.
+1 -1
View File
@@ -193,7 +193,7 @@ void PopupScreen::CreateViews() {
box_->SetRadiusFactor(1.44f);
// Since we scale a bit, make the dropshadow bleed past the edges.
box_->SetDropShadowExpand(std::max(g_display.dp_xres, g_display.dp_yres));
box_->SetSpacing(0.0f);
box_->SetSpacing(12.0f);
box_->SetPadding(Margins(12));
if (!title_.empty()) {
+53 -37
View File
@@ -641,6 +641,59 @@ std::string ItemHeader::DescribeText() const {
return ApplySafeSubstitutions(u->T("%1 heading"), text_);
}
PopupHeader::PopupHeader(std::string_view text, LayoutParams *layoutParams)
: Item(layoutParams), text_(text) {
layoutParams_->width = FILL_PARENT;
layoutParams_->height = 44;
}
void PopupHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const {
float availWidth = layoutParams_->width;
if (availWidth < 0) {
// If there's no size, let's grow as big as we want.
availWidth = horiz.size == 0 ? MAX_ITEM_SIZE : horiz.size;
}
ApplyBoundBySpec(availWidth, horiz);
dc.MeasureTextRect(dc.GetTheme().uiFontBig, 1.0f, 1.0f, text_, availWidth, &w, &h, ALIGN_LEFT | ALIGN_VCENTER);
}
void PopupHeader::Draw(UIContext &dc) {
const float availableWidth = bounds_.w;
float tw, th;
dc.SetFontStyle(dc.GetTheme().uiFontBig);
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_, &tw, &th, 0);
float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f;
float tx = 0;
if (availableWidth < tw) {
float overageRatio = 1.5f * availableWidth * 1.0f / tw;
tx -= (1.0f + sin(time_now_d() * overageRatio)) * sineWidth;
Bounds tb = bounds_;
tb.x = bounds_.x;
tb.w = bounds_.w;
dc.PushScissor(tb);
}
// Header background
dc.FillRoundRect(dc.GetTheme().popupTitleStyle.background, bounds_, dc.GetTheme().choiceRoundRadius, roundCorners_);
// Header title text
dc.DrawText(text_, bounds_.x + tx, bounds_.centerY(), dc.GetTheme().popupTitleStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER);
// Underline. Skipping it with the new style.
// dc.Draw()->DrawImageCenterTexel(dc.GetTheme().whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.GetTheme().popupTitleStyle.fgColor);
if (availableWidth < tw) {
dc.PopScissor();
}
}
std::string PopupHeader::DescribeText() const {
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
return ApplySafeSubstitutions(u->T("%1 heading"), text_);
}
CollapsibleHeader::CollapsibleHeader(bool *toggle, std::string_view text, LayoutParams *layoutParams)
: CheckBox(toggle, text, "", layoutParams) {
layoutParams_->width = FILL_PARENT;
@@ -713,43 +766,6 @@ void BorderView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec hor
h = (borderFlags_ & BORDER_HORIZ) != 0 ? bounds.h : 0;
}
void PopupHeader::Draw(UIContext &dc) {
const float availableWidth = bounds_.w;
float tw, th;
dc.SetFontStyle(dc.GetTheme().uiFontBig);
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_, &tw, &th, 0);
float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f;
float tx = 0;
if (availableWidth < tw) {
float overageRatio = 1.5f * availableWidth * 1.0f / tw;
tx -= (1.0f + sin(time_now_d() * overageRatio)) * sineWidth;
Bounds tb = bounds_;
tb.x = bounds_.x;
tb.w = bounds_.w;
dc.PushScissor(tb);
}
// Header background
dc.FillRoundRect(dc.GetTheme().popupTitleStyle.background, bounds_, dc.GetTheme().choiceRoundRadius, roundCorners_);
// Header title text
dc.DrawText(text_, bounds_.x + tx, bounds_.centerY(), dc.GetTheme().popupTitleStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER);
// Underline. Skipping it with the new style.
// dc.Draw()->DrawImageCenterTexel(dc.GetTheme().whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.GetTheme().popupTitleStyle.fgColor);
if (availableWidth < tw) {
dc.PopScissor();
}
}
std::string PopupHeader::DescribeText() const {
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
return ApplySafeSubstitutions(u->T("%1 heading"), text_);
}
void CheckBox::Toggle() {
if (toggle_) {
*toggle_ = !(*toggle_);
+2 -5
View File
@@ -939,12 +939,9 @@ private:
class PopupHeader : public Item {
public:
PopupHeader(std::string_view text, LayoutParams *layoutParams = 0)
: Item(layoutParams), text_(text) {
layoutParams_->width = FILL_PARENT;
layoutParams_->height = 64;
}
PopupHeader(std::string_view text, LayoutParams *layoutParams = 0);
void Draw(UIContext &dc) override;
void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override;
std::string DescribeText() const override;
private:
+1 -1
View File
@@ -145,7 +145,7 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
// Show the savedata popup, why not?
waitForParamSFO();
std::string title = SanitizeString(info->GetTitle(), StringRestriction::NoLineBreaksOrSpecials, 0, 200);
screenManager->push(new SavedataPopupScreen(Path(), path, title));
screenManager->push(new SavedataPopupScreen(Path(), path, true, title));
return;
}
case IdentifiedFileType::PSP_PBP:
+3 -1
View File
@@ -192,7 +192,7 @@ void MemStickScreen::CreateViews() {
ViewGroup *leftColumn = new LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(1.0));
subColumns->Add(leftColumn);
ViewGroup *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(250, FILL_PARENT, actionMenuMargins));
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(250, FILL_PARENT, actionMenuMargins));
subColumns->Add(rightColumnItems);
// For legacy Android systems, so you can switch back to the old ways if you move to SD or something.
@@ -276,6 +276,8 @@ void MemStickScreen::CreateViews() {
rightColumnItems->Add(new UI::Choice(ms->T("WhatsThis", "What's this?"), ImageID("I_LINK_OUT_QUESTION")))->OnClick.Handle<MemStickScreen>(this, &MemStickScreen::OnHelp);
}
rightColumnItems->ApplyRoundCorners();
INFO_LOG(Log::System, "MemStickScreen: initialSetup=%d", (int)initialSetup_);
}
+12
View File
@@ -167,3 +167,15 @@ private:
int width_ = 0;
int height_ = 0;
};
class HintView : public UI::TextView {
public:
HintView(std::string_view str, UI::LayoutParams *layoutParams = nullptr) : TextView(str, FLAG_WRAP_TEXT, false, layoutParams) {
using namespace UI;
layoutParams_->width = FILL_PARENT;
layoutParams_->height = WRAP_CONTENT;
SetTextSize(TextSize::Small);
SetPadding(Margins(12));
SetFrame(true);
}
};
+3
View File
@@ -904,6 +904,9 @@ void NativeInit(int argc, const char *argv[], const CommandLineOptions &cmdLineO
} else if (equals(cmdLineOptions.startScreen.value(), "firmware")) {
g_screenManager->switchScreen(new MainScreen());
g_screenManager->push(new FirmwareScreen(Path()));
} else if (equals(cmdLineOptions.startScreen.value(), "memsticksetup")) {
g_screenManager->switchScreen(new MainScreen());
g_screenManager->push(new MemStickScreen(true));
} else {
WARN_LOG(Log::System, "Unknown start screen '%s'", cmdLineOptions.startScreen.value().c_str());
g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::DEFAULT));
+3 -3
View File
@@ -497,14 +497,14 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems,
LinearLayout *buttonRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(Margins(10, 0, 0, 10)));
if (g_Config.bEnableStateUndo && !Achievements::HardcoreModeActive() && NetworkAllowSaveState()) {
UI::Choice *saveUndoButton = buttonRow->Add(new Choice(pa->T("Undo last save"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
UI::Button *saveUndoButton = buttonRow->Add(new Button(pa->T("Undo last save"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(WRAP_CONTENT, ITEM_HEIGHT)));
saveUndoButton->SetEnabled(SaveState::HasUndoLastSave(saveStatePrefix_));
saveUndoButton->OnClick.Add([this](UI::EventParams &e) {
SaveState::UndoLastSave(saveStatePrefix_);
RecreateViews();
});
UI::Choice *loadUndoButton = buttonRow->Add(new Choice(pa->T("Undo last load"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
UI::Button *loadUndoButton = buttonRow->Add(new Button(pa->T("Undo last load"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(WRAP_CONTENT, ITEM_HEIGHT)));
loadUndoButton->SetEnabled(SaveState::HasUndoLoad(saveStatePrefix_));
loadUndoButton->OnClick.Add([this](UI::EventParams &e) {
CloseAfterStateLoad([this](SaveState::Callback callback) {
@@ -514,7 +514,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems,
}
if (g_Config.iRewindSnapshotInterval > 0 && !Achievements::HardcoreModeActive() && NetworkAllowSaveState()) {
UI::Choice *rewindButton = buttonRow->Add(new Choice(pa->T("Rewind"), ImageID("I_REWIND"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
UI::Button *rewindButton = buttonRow->Add(new Button(pa->T("Rewind"), ImageID("I_REWIND"), new LinearLayoutParams(WRAP_CONTENT, ITEM_HEIGHT)));
rewindButton->SetEnabled(SaveState::CanRewind());
rewindButton->OnClick.Add([this](UI::EventParams &e) {
CloseAfterStateLoad([](SaveState::Callback callback) {
+15 -8
View File
@@ -132,7 +132,7 @@ SavedataView::SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType ty
}
}
SavedataPopupScreen::SavedataPopupScreen(Path gamePath, Path savePath, std::string_view title) : PopupScreen(StripSpaces(title)), savePath_(savePath), gamePath_(gamePath) {}
SavedataPopupScreen::SavedataPopupScreen(Path gamePath, Path savePath, bool showHint, std::string_view title) : PopupScreen(StripSpaces(title)), savePath_(savePath), gamePath_(gamePath), showHint_(showHint) {}
void SavedataPopupScreen::update() {
PopupScreen::update();
@@ -158,17 +158,23 @@ void SavedataPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
ScrollView *contentScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f, UI::Margins(0, 3)));
parent->Add(contentScroll);
LinearLayout *content = contentScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
if (showHint_) {
auto g = GetI18NCategory(I18NCat::GAME);
content->Add(new HintView(g->T("SaveData")));
}
// TODO: If the game info wasn't already loaded, we'll get a bogus fileType here.
savedataView_ = contentScroll->Add(new SavedataView(dc, ginfo.get(), ginfo->fileType, true));
savedataView_ = content->Add(new SavedataView(dc, ginfo.get(), ginfo->fileType, true));
auto di = GetI18NCategory(I18NCat::DIALOG);
LinearLayout *buttonRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
buttonRow->SetSpacing(0);
Margins buttonMargins(5, 5, 5, 13); // not sure why we need more at the bottom to make it look right
buttonRow->SetSpacing(12);
buttonRow->Add(new Choice(di->T("Back"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
buttonRow->Add(new Choice(di->T("Delete"), ImageID("I_TRASHCAN"), new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Add([this](UI::EventParams &e) {
buttonRow->Add(new Choice(di->T("Back"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(1.0f)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
buttonRow->Add(new Choice(di->T("Delete"), ImageID("I_TRASHCAN"), new LinearLayoutParams(1.0f)))->OnClick.Add([this](UI::EventParams &e) {
auto di = GetI18NCategory(I18NCat::DIALOG);
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(nullptr, savePath_, GameInfoFlags::PARAM_SFO);
@@ -183,10 +189,11 @@ void SavedataPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
}));
});
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
buttonRow->Add(new Choice(di->T("Show in folder"), ImageID("I_FOLDER"), new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Add([this](UI::EventParams &e) {
buttonRow->Add(new Choice(di->T("Show in folder"), ImageID("I_FOLDER"), new LinearLayoutParams(1.0f)))->OnClick.Add([this](UI::EventParams &e) {
System_ShowFileInFolder(savePath_);
});
}
buttonRow->ApplyRoundCorners();
parent->Add(buttonRow);
}
@@ -690,7 +697,7 @@ void SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) {
// Sanitize the title.
std::string title = SanitizeString(ginfo->GetTitle(), StringRestriction::NoLineBreaksOrSpecials, 0, 200);
SavedataPopupScreen *popupScreen = new SavedataPopupScreen(gamePath_, Path(e.s), title);
SavedataPopupScreen *popupScreen = new SavedataPopupScreen(gamePath_, Path(e.s), false, title);
if (e.v) {
popupScreen->SetPopupOrigin(e.v);
}
+2 -1
View File
@@ -71,7 +71,7 @@ class SavedataView;
class SavedataPopupScreen : public UI::PopupScreen {
public:
SavedataPopupScreen(Path gamePath, Path savePath, std::string_view title);
SavedataPopupScreen(Path gamePath, Path savePath, bool showHint, std::string_view title);
const char *tag() const override { return "SavedataPopup"; }
void update() override;
@@ -84,6 +84,7 @@ private:
SavedataView *savedataView_ = nullptr;
Path savePath_;
Path gamePath_;
bool showHint_ = false;
};
class SavedataScreen : public UITabbedBaseDialogScreen {