diff --git a/Common/Log.cpp b/Common/Log.cpp index f95bb7549c..2937c0f308 100644 --- a/Common/Log.cpp +++ b/Common/Log.cpp @@ -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 +} diff --git a/Common/Log.h b/Common/Log.h index 198c765b6a..26abef28f6 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -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. diff --git a/Common/Render/Text/Font.h b/Common/Render/Text/Font.h index e1ebf6bb6d..d166b2b97a 100644 --- a/Common/Render/Text/Font.h +++ b/Common/Render/Text/Font.h @@ -21,7 +21,8 @@ ENUM_CLASS_BITOPS(FontStyleFlags); enum class FontFamily : u8 { SansSerif = 1, - Fixed = 2, + SansSerifWide = 2, + Fixed = 3, }; struct FontStyle { diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index 49dc15c13d..8d2eb1a749 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -400,6 +400,10 @@ static const FontDesc g_fontDescs[] = { {FontFamily::SansSerif, FontStyleFlags::Bold, "Roboto Condensed", "Roboto_Condensed-Bold"}, {FontFamily::SansSerif, FontStyleFlags::Italic, "Roboto Condensed", "Roboto_Condensed-Italic"}, {FontFamily::SansSerif, FontStyleFlags::Light, "Roboto Condensed", "Roboto_Condensed-Light"}, + {FontFamily::SansSerifWide, FontStyleFlags::Default, "Roboto SemiCondensed", "Roboto_SemiCondensed-Regular"}, + {FontFamily::SansSerifWide, FontStyleFlags::Bold, "Roboto SemiCondensed", "Roboto_SemiCondensed-Bold"}, + {FontFamily::SansSerifWide, FontStyleFlags::Italic, "Roboto SemiCondensed", "Roboto_SemiCondensed-Italic"}, + {FontFamily::SansSerifWide, FontStyleFlags::Light, "Roboto SemiCondensed", "Roboto_SemiCondensed-Light"}, {FontFamily::Fixed, FontStyleFlags::Default, "Inconsolata", "Inconsolata-Regular"}, }; diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 9c49c9f7a0..e7a301ebb8 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -153,6 +153,7 @@ void PopupScreen::CreateViews() { using namespace UI; UIContext &dc = *screenManager()->getUIContext(); + // This places the actual popup in the center of the screen. AnchorLayout *anchor = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); anchor->Overflow(false); root_ = anchor; @@ -184,16 +185,16 @@ void PopupScreen::CreateViews() { (layoutBounds.w - RootMargins().horiz()) * 0.5, y, NONE, NONE, vCentering | Centering::Horizontal); } - box_ = new LinearLayout(ORIENT_VERTICAL, anchorParams); + // Box is the actual popup shape. + box_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, anchorParams)); - root_->Add(box_); box_->SetBG(dc.GetTheme().popupStyle.background); box_->SetHasDropShadow(hasDropShadow_); 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_->SetPadding(Margins(8)); + box_->SetSpacing(12.0f); + box_->SetPadding(Margins(12)); if (!title_.empty()) { View *title = new PopupHeader(title_); @@ -214,21 +215,19 @@ void PopupScreen::CreateViews() { if (ShowButtons() && !button1_.empty()) { // And the two buttons at the bottom. LinearLayout *buttonRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(200, WRAP_CONTENT)); - buttonRow->SetSpacing(0); - Margins buttonMargins(5, 5); - + buttonRow->SetSpacing(8); // Adjust button order to the platform default. if (System_GetPropertyBool(SYSPROP_OK_BUTTON_LEFT)) { - defaultButton_ = buttonRow->Add(new Choice(button1_, button1Image_, new LinearLayoutParams(1.0f, buttonMargins))); + defaultButton_ = buttonRow->Add(new Choice(button1_, button1Image_, new LinearLayoutParams(1.0f))); defaultButton_->OnClick.Handle(this, &UIScreen::OnOK); if (!button2_.empty()) { - buttonRow->Add(new Choice(button2_, button2Image_, new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Handle(this, &UIScreen::OnCancel); + buttonRow->Add(new Choice(button2_, button2Image_, new LinearLayoutParams(1.0f)))->OnClick.Handle(this, &UIScreen::OnCancel); } } else { if (!button2_.empty()) { - buttonRow->Add(new Choice(button2_, button2Image_, new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Handle(this, &UIScreen::OnCancel); + buttonRow->Add(new Choice(button2_, button2Image_, new LinearLayoutParams(1.0f)))->OnClick.Handle(this, &UIScreen::OnCancel); } - defaultButton_ = buttonRow->Add(new Choice(button1_, button1Image_, new LinearLayoutParams(1.0f, buttonMargins))); + defaultButton_ = buttonRow->Add(new Choice(button1_, button1Image_, new LinearLayoutParams(1.0f))); defaultButton_->OnClick.Handle(this, &UIScreen::OnOK); } @@ -256,12 +255,8 @@ void MessagePopupScreen::CreatePopupContents(UI::ViewGroup *parent) { } void MessagePopupScreen::OnCompleted(DialogResult result) { - if (result == DR_OK) { - if (callback_) - callback_(true); - } else { - if (callback_) - callback_(false); + if (callback_) { + callback_(result == DR_OK); } } diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 060691c2da..0f7b8140a6 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -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,44 +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 paddingHorizontal = 12; - const float availableWidth = bounds_.w - paddingHorizontal * 2; - - float tw, th; - dc.SetFontStyle(dc.GetTheme().uiFont); - dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_, &tw, &th, 0); - - float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; - - float tx = paddingHorizontal; - 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 + paddingHorizontal; - tb.w = bounds_.w - paddingHorizontal * 2; - 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_); diff --git a/Common/UI/View.h b/Common/UI/View.h index dbddad7079..70fc2508d9 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -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: diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index c0de3143c2..f35ed4b6d7 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -885,7 +885,14 @@ ChoiceGroup::ChoiceGroup(std::string_view title, LayoutParams *layoutParams) ChoiceGroupList::ChoiceGroupList(LayoutParams *layoutParams) : LinearLayoutList(ORIENT_VERTICAL, layoutParams ? layoutParams : new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)) { - SetPadding(Margins(12, 12, 8, 12)); + SetPadding(Margins(12, 12, 12, 12)); + SetSpacing(24.0f); +} + +PopupChoiceGroupList::PopupChoiceGroupList(LayoutParams *layoutParams) + : LinearLayoutList(ORIENT_VERTICAL, layoutParams ? layoutParams : new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)) { + // Padding is already present in the popup itself. Just add a little more. + SetPadding(Margins(0)); SetSpacing(24.0f); } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index bb4726219f..78084527c3 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -276,6 +276,13 @@ public: ChoiceGroupList(LayoutParams *layoutParams = nullptr); }; +// A vertical list that spaces out the ChoiceGroups in it and keeps them off its edges. +// This one is adjusted for popups (i.e. smaller margins and spacing). +class PopupChoiceGroupList : public LinearLayoutList { +public: + PopupChoiceGroupList(LayoutParams *layoutParams = nullptr); +}; + // GridLayout is a little different from the Android layout. This one has fixed size // rows and columns, filled row by row. Items are not allowed to deviate from the set sizes. struct GridLayoutSettings { diff --git a/Core/CmdLine.cpp b/Core/CmdLine.cpp index 534312fe12..32ab112c25 100644 --- a/Core/CmdLine.cpp +++ b/Core/CmdLine.cpp @@ -557,6 +557,17 @@ CommandLineParseResult CommandLineOptions::Parse(int argc, const char *argv[], C } } else if (startsWith(argv[i], "--")) { PRINT_STDERR("Error: Unknown parameter: %s\n", argv[i]); + if (mode == CmdLineMode::Application) { + // Ignore bad parameters - but inform the user in the Windows debug output at least. + OutputDebugStringUTF8("Warning: Unknown parameter: "); + OutputDebugStringUTF8(argv[i]); + OutputDebugStringUTF8("\n"); + + std::string msg = StringFromFormat("Unknown command line parameter: %s\n\nProceeding anyway.", argv[i]); + ShowMessageDialog("Unknown Parameter", msg.c_str(), true); + + return CommandLineParseResult::Continue; + } return CommandLineParseResult::Error; } // To the next argument. diff --git a/UI/GameButton.cpp b/UI/GameButton.cpp index 567ad237af..56a0675833 100644 --- a/UI/GameButton.cpp +++ b/UI/GameButton.cpp @@ -342,6 +342,8 @@ void GameButton::Draw(UIContext &dc) { dc.PopScissor(); } } else { + // The two list view modes, compat and large. + Bounds bounds = bounds_; std::string_view rightText = g_Config.bShowIDOnGameIcon ? std::string_view(id_version) : std::string_view(); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index e9e9a75f18..c849745382 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -396,17 +396,26 @@ bool GameInfo::DeleteAllSaveData() const { void GameInfo::ParseParamSFO(IdentifiedFileType type) { title = paramSFO.GetValueString("TITLE"); - if (type != IdentifiedFileType::PSP_UMD_VIDEO_ISO) { + switch (type) { + case IdentifiedFileType::PSP_UMD_VIDEO_ISO: + id.clear(); + id_version.clear(); + region = GameRegion::UNKNOWN; + break; + case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: + // Sniff the ID from the folder name. + id = paramSFO.GetValueString("SAVEDATA_DIRECTORY").substr(0, 9); + id_version = id; + region = DetectGameRegionFromID(id); + break; + default: id = paramSFO.GetValueString("DISC_ID"); id_version = id + "_" + paramSFO.GetValueString("DISC_VERSION"); disc_total = paramSFO.GetValueInt("DISC_TOTAL"); disc_number = paramSFO.GetValueInt("DISC_NUMBER"); // region = paramSFO.GetValueInt("REGION"); // Always seems to be 32768? region = DetectGameRegionFromID(id); - } else { - id.clear(); - id_version.clear(); - region = GameRegion::UNKNOWN; + break; } } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 73b54116b3..c6b9e28bfb 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -135,7 +135,7 @@ static const PageDef pageDefs[] = { { "GameSettingsNetworking", "Networking", "I_WIFI", "network", I18NCat::NETWORKING, &BuildNetworkingSettings }, { "GameSettingsTools", "Tools", "I_TOOLS", "tools", I18NCat::MAINSETTINGS, &BuildToolsSettings }, { "GameSettingsSystem", "System", "I_PSP", "system", I18NCat::SYSTEM, nullptr, &BuildSystemSettings }, - { "GameSettingsVR", "VR", nullptr, nullptr, I18NCat::VR, &BuildVRSettings }, + { "GameSettingsVR", "VR", "I_VR", nullptr, I18NCat::VR, &BuildVRSettings}, }; void GameSettingsScreen::CreateTabs() { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 8e8f41ae02..a6079b36ee 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1949,7 +1949,7 @@ static const char *VoiceTypeToString(VoiceType type) { } } -void DrawSasAudio(ImConfig &cfg) { +static void DrawSasAudio(ImConfig &cfg, ImControl &control) { if (!ImGui::Begin("sasAudio", &cfg.sasAudioOpen)) { ImGui::End(); return; @@ -2012,8 +2012,8 @@ void DrawSasAudio(ImConfig &cfg) { ImGui::TableNextColumn(); switch (voice.type) { case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; - case VOICETYPE_VAG: ImGui::Text("%08x", voice.vagAddr); break; - case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmAddr); break; + case VOICETYPE_VAG: ImClickableValue("vagaddr", voice.vagAddr, control, ImCmd::SHOW_IN_MEMORY_VIEWER); break; + case VOICETYPE_PCM: ImClickableValue("pcmaddr", voice.pcmAddr, control, ImCmd::SHOW_IN_MEMORY_VIEWER); break; case VOICETYPE_ATRAC3: ImGui::Text("atrac: %d", voice.atrac3.AtracID()); break; default: ImGui::TextUnformatted("N/A"); @@ -2022,8 +2022,8 @@ void DrawSasAudio(ImConfig &cfg) { ImGui::TableNextColumn(); switch (voice.type) { case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; - case VOICETYPE_VAG: ImGui::Text("%08x", voice.vagSize); break; - case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmSize); break; + case VOICETYPE_VAG: ImGui::Text("%x", voice.vagSize); break; + case VOICETYPE_PCM: ImGui::Text("%x", voice.pcmSize); break; case VOICETYPE_ATRAC3: ImGui::Text("atrac: n/a"); break; default: ImGui::TextUnformatted("N/A"); @@ -3165,7 +3165,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: } if (cfg_.sasAudioOpen) { - DrawSasAudio(cfg_); + DrawSasAudio(cfg_, control); } if (cfg_.kernelObjectsOpen) { diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index 855f5ed03b..63b8cc9d14 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -1434,7 +1434,7 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD if (gstate.isModeClear()) { ImGui::Text("(clear mode - texturing not used)"); } else if (!gstate.isTextureMapEnabled()) { - ImGui::Text("(texturing not enabled"); + ImGui::Text("(texturing not enabled)"); } else if (TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon()) { // We don't bother with the texture if previewCmd is BOUNDING_BOX - no texturing happens there. TextureApplyResult result = texcache->ApplyTexture(false); if (TexCacheEntry *tex = result.texCacheEntry) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index c8548bbbc4..deb7c7f67a 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -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: @@ -992,7 +992,9 @@ void UmdReplaceScreen::CreateViews() { rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle(this, &UIScreen::OnCancel); rightColumnItems->Add(new Spacer()); - rightColumnItems->Add(new Choice(mm->T("Game Settings")))->OnClick.Handle(this, &UmdReplaceScreen::OnGameSettings); + rightColumnItems->Add(new Choice(mm->T("Game Settings")))->OnClick.Add([this](UI::EventParams &e) { + screenManager()->push(new GameSettingsScreen(Path())); + }); if (g_recentFiles.HasAny()) { leftColumn->SetCurrentTab(0, true); @@ -1026,10 +1028,6 @@ void UmdReplaceScreen::UseDisc(const Path &path) { } } -void UmdReplaceScreen::OnGameSettings(UI::EventParams &e) { - screenManager()->push(new GameSettingsScreen(Path())); -} - void GridSettingsPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; @@ -1037,41 +1035,36 @@ void GridSettingsPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { auto sy = GetI18NCategory(I18NCat::SYSTEM); auto mm = GetI18NCategory(I18NCat::MAINMENU); - ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f)); - LinearLayout *items = new LinearLayoutList(ORIENT_VERTICAL); - items->SetSpacing(0.0f); + ScrollView *scroll = parent->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f))); + + PopupChoiceGroupList *groupList = scroll->Add(new PopupChoiceGroupList()); + + ChoiceGroup *group = groupList->Add(new ChoiceGroup()); // Same order as GameBrowserViewMode. static const char *defaultTabs[] = { "Recent", "Games", "Homebrew & Demos" }; - items->Add(new PopupMultiChoice(&g_Config.iDefaultTab, sy->T("Default tab"), defaultTabs, 0, ARRAY_SIZE(defaultTabs), I18NCat::MAINMENU, screenManager())); + group->Add(new PopupMultiChoice(&g_Config.iDefaultTab, sy->T("Default tab"), defaultTabs, 0, ARRAY_SIZE(defaultTabs), I18NCat::MAINMENU, screenManager())); - 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); + ChoiceGroup *iconSizeGroup = groupList->Add(new ChoiceGroup(sy->T("Icon size"))); + iconSizeGroup->Add(new Choice(sy->T("Increase size")))->OnClick.Add([this](UI::EventParams &e) { + g_Config.fGameGridScale = std::min(g_Config.fGameGridScale * 1.25f, MAX_GAME_GRID_SCALE); + screenManager()->RecreateAllViews(); + }); + iconSizeGroup->Add(new Choice(sy->T("Decrease size")))->OnClick.Add([this](UI::EventParams &e) { + g_Config.fGameGridScale = std::max(g_Config.fGameGridScale / 1.25f, MIN_GAME_GRID_SCALE); + screenManager()->RecreateAllViews(); + }); - items->Add(new ItemHeader(sy->T("Display Extra Info"))); - items->Add(new CheckBox(&g_Config.bShowIDOnGameIcon, sy->T("Show ID"))); - items->Add(new CheckBox(&g_Config.bShowRegionOnGameIcon, sy->T("Show region flag"))); + ChoiceGroup *extraInfoGroup = groupList->Add(new ChoiceGroup(sy->T("Display Extra Info"))); + extraInfoGroup->Add(new CheckBox(&g_Config.bShowIDOnGameIcon, sy->T("Show ID"))); + extraInfoGroup->Add(new CheckBox(&g_Config.bShowRegionOnGameIcon, sy->T("Show region flag"))); if (g_Config.iMaxRecent > 0) { - items->Add(new ItemHeader(sy->T("Clear Recent"))); - items->Add(new Choice(sy->T("Clear Recent Games List")))->OnClick.Handle(this, &GridSettingsPopupScreen::OnRecentClearClick); + ChoiceGroup *recentGroup = groupList->Add(new ChoiceGroup(sy->T("Clear Recent"))); + recentGroup->Add(new Choice(sy->T("Clear Recent Games List")))->OnClick.Add([this](UI::EventParams &e) { + g_recentFiles.Clear(); + OnRecentChanged.Trigger(e); + TriggerFinish(DR_OK); + }); } - - scroll->Add(items); - parent->Add(scroll); -} - -void GridSettingsPopupScreen::GridPlusClick(UI::EventParams &e) { - g_Config.fGameGridScale = std::min(g_Config.fGameGridScale*1.25f, MAX_GAME_GRID_SCALE); -} - -void GridSettingsPopupScreen::GridMinusClick(UI::EventParams &e) { - g_Config.fGameGridScale = std::max(g_Config.fGameGridScale/1.25f, MIN_GAME_GRID_SCALE); -} - -void GridSettingsPopupScreen::OnRecentClearClick(UI::EventParams &e) { - g_recentFiles.Clear(); - OnRecentChanged.Trigger(e); - TriggerFinish(DR_OK); } diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 2a21b9e6f9..525c964267 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -115,7 +115,6 @@ protected: private: void OnGameSelected(UI::EventParams &e); - void OnGameSettings(UI::EventParams &e); void UseDisc(const Path &path); bool insert_; @@ -130,9 +129,6 @@ public: const char *tag() const override { return "GridSettings"; } private: - void GridPlusClick(UI::EventParams &e); - void GridMinusClick(UI::EventParams &e); - void OnRecentClearClick(UI::EventParams &e); const float MAX_GAME_GRID_SCALE = 3.0f; const float MIN_GAME_GRID_SCALE = 0.8f; }; diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index a9369b003b..c3f2c2bdfa 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -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(this, &MemStickScreen::OnHelp); } + rightColumnItems->ApplyRoundCorners(); + INFO_LOG(Log::System, "MemStickScreen: initialSetup=%d", (int)initialSetup_); } diff --git a/UI/MiscViews.h b/UI/MiscViews.h index e5b0285482..e0b20fa2b3 100644 --- a/UI/MiscViews.h +++ b/UI/MiscViews.h @@ -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); + } +}; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index ad91aa7a6b..7d3eaa4243 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -373,7 +373,7 @@ void runImDebugger(Draw::DrawContext *draw) { // Read the TTF font size_t propSize = 0; - const uint8_t *propFontData = g_VFS.ReadFile("Roboto-Regular.ttf", &propSize); + const uint8_t *propFontData = g_VFS.ReadFile("Roboto_Condensed-Regular.ttf", &propSize); size_t fixedSize = 0; const uint8_t *fixedFontData = g_VFS.ReadFile("Inconsolata-Regular.ttf", &fixedSize); // This call works even if fontData is nullptr, in which case the font just won't get loaded. @@ -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)); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 5208b93a8d..0e5b6f3ae9 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -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) { @@ -661,12 +661,12 @@ void GamePauseScreen::CreateViews() { if (showSavestateControls) { if (PSP_CoreParameter().compat.flags().SaveStatesNotRecommended) { - LinearLayout *horiz = new LinearLayout(ORIENT_HORIZONTAL); - saveDataScrollItems->Add(horiz); + LinearLayout *horiz = saveDataScrollItems->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); horiz->Add(new NoticeView(NoticeLevel::WARN, pa->T("Using save states is not recommended in this game"), "", new LinearLayoutParams(1.0f))); - horiz->Add(new Button(di->T("More info")))->OnClick.Add([](UI::EventParams &e) { + horiz->Add(new Choice(di->T("More info"), ImageID("I_LINK_OUT_QUESTION"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)))->OnClick.Add([](UI::EventParams &e) { System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/troubleshooting/save-state-time-warps"); }); + horiz->ApplyRoundCorners(); } LinearLayout *extraRow = nullptr; CreateSavestateControls(saveDataScrollItems, &extraRow); diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 0e0977e8dc..645a6d4ded 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -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(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(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 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); } diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 66fdce3463..c0040b0795 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -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 { diff --git a/UI/UIAtlas.cpp b/UI/UIAtlas.cpp index 0d7469c6c4..d8cc8c9d5a 100644 --- a/UI/UIAtlas.cpp +++ b/UI/UIAtlas.cpp @@ -208,6 +208,7 @@ static const ImageMeta g_uiImageIDs[] = { {"I_DOWNLOAD", false}, {"I_NETWORK", false}, {"I_LANGUAGE", false}, + {"I_VR", false}, }; static std::string PNGNameFromID(std::string_view id) { diff --git a/assets/Roboto_SemiCondensed-Bold.ttf b/assets/Roboto_SemiCondensed-Bold.ttf new file mode 100644 index 0000000000..3b09bdc9f8 Binary files /dev/null and b/assets/Roboto_SemiCondensed-Bold.ttf differ diff --git a/assets/Roboto_SemiCondensed-Italic.ttf b/assets/Roboto_SemiCondensed-Italic.ttf new file mode 100644 index 0000000000..fb944fba80 Binary files /dev/null and b/assets/Roboto_SemiCondensed-Italic.ttf differ diff --git a/assets/Roboto_SemiCondensed-Light.ttf b/assets/Roboto_SemiCondensed-Light.ttf new file mode 100644 index 0000000000..aa2fd112e7 Binary files /dev/null and b/assets/Roboto_SemiCondensed-Light.ttf differ diff --git a/assets/Roboto_SemiCondensed-Regular.ttf b/assets/Roboto_SemiCondensed-Regular.ttf new file mode 100644 index 0000000000..462fe489ef Binary files /dev/null and b/assets/Roboto_SemiCondensed-Regular.ttf differ diff --git a/assets/ui_images/images.svg b/assets/ui_images/images.svg index 0870ff52fe..eb4b22ef39 100644 --- a/assets/ui_images/images.svg +++ b/assets/ui_images/images.svg @@ -23,9 +23,9 @@ inkscape:pagecheckerboard="true" inkscape:deskcolor="#d1d1d1" inkscape:document-units="px" - inkscape:zoom="5.6568544" - inkscape:cx="181.63805" - inkscape:cy="75.041705" + inkscape:zoom="4.0000001" + inkscape:cx="234.87499" + inkscape:cy="537.87499" inkscape:window-width="3840" inkscape:window-height="2071" inkscape:window-x="-9" @@ -985,7 +985,7 @@ style="fill:#ffffff;stroke-width:4.93273" d="m 94.191649,3.89538 a 2.5724686,2.5724686 0 0 1 2.57247,-2.57246 2.5724686,2.5724686 0 0 1 2.57247,2.57246 2.5724686,2.5724686 0 0 1 -2.57247,2.57247 2.5724686,2.5724686 0 0 1 -2.57247,-2.57247 z" /> + transform="matrix(1.8233708,0,0,1.8233708,-118.84776,-1.0582382)">