GameScreen: New look in portrait mode

This commit is contained in:
Henrik Rydgård committed 2025-11-15 20:44:14 +01:00
1 parent 3d20251500
commit 57507ec9e6
10 files changed
+82 -41

No files matched your search

+3 -3
View File
@@ -480,7 +480,7 @@ void KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) {
}
}
AnalogCalibrationScreen::AnalogCalibrationScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath) {
AnalogCalibrationScreen::AnalogCalibrationScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::Default) {
mapper_.SetCallbacks(
[](int vkey, bool down) {},
[](int vkey, float analogValue) {},
@@ -535,7 +535,7 @@ std::string_view AnalogCalibrationScreen::GetTitle() const {
return co->T("Calibrate analog stick");
}
void AnalogCalibrationScreen::CreateSettingsViews(UI::LinearLayout *scrollContents) {
void AnalogCalibrationScreen::CreateSettingsViews(UI::ViewGroup *scrollContents) {
using namespace UI;
auto co = GetI18NCategory(I18NCat::CONTROLS);
@@ -551,7 +551,7 @@ void AnalogCalibrationScreen::CreateSettingsViews(UI::LinearLayout *scrollConten
scrollContents->Add(new Choice(co->T("Reset to defaults")))->OnClick.Handle(this, &AnalogCalibrationScreen::OnResetToDefaults);
}
void AnalogCalibrationScreen::CreateContentViews(UI::LinearLayout *parent) {
void AnalogCalibrationScreen::CreateContentViews(UI::ViewGroup *parent) {
using namespace UI;
auto co = GetI18NCategory(I18NCat::CONTROLS);
+2 -2
View File
@@ -137,8 +137,8 @@ public:
const char *tag() const override { return "AnalogSetup"; }
protected:
void CreateSettingsViews(UI::LinearLayout *parent) override;
void CreateContentViews(UI::LinearLayout *parent) override;
void CreateSettingsViews(UI::ViewGroup *parent) override;
void CreateContentViews(UI::ViewGroup *parent) override;
std::string_view GetTitle() const override;
private:
+16 -7
View File
@@ -56,7 +56,7 @@
constexpr GameInfoFlags g_desiredFlags = GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::PIC0 | GameInfoFlags::PIC1 | GameInfoFlags::UNCOMPRESSED_SIZE | GameInfoFlags::SIZE;
GameScreen::GameScreen(const Path &gamePath, bool inGame) : UITwoPaneBaseDialogScreen(gamePath), inGame_(inGame) {
GameScreen::GameScreen(const Path &gamePath, bool inGame) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::SettingsToTheRight | TwoPaneFlags::SettingsInContextMenu), inGame_(inGame) {
g_BackgroundAudio.SetGame(gamePath);
System_PostUIMessage(UIMessage::GAME_SELECTED, gamePath.ToString());
@@ -119,7 +119,7 @@ static bool FileTypeSupportsCRC(IdentifiedFileType fileType) {
}
}
void GameScreen::CreateContentViews(UI::LinearLayout *parent) {
void GameScreen::CreateContentViews(UI::ViewGroup *parent) {
if (!info_) {
// Shouldn't happen
return;
@@ -137,8 +137,13 @@ void GameScreen::CreateContentViews(UI::LinearLayout *parent) {
Margins actionMenuMargins(0, 15, 15, 0);
ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f, Margins(8)));
parent->Add(leftColumn);
ScrollView *leftScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f, Margins(8)));
ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
leftScroll->Add(leftColumn);
parent->Add(leftScroll);
const bool fileTypeSupportCRC = FileTypeSupportsCRC(info_->fileType);
@@ -295,21 +300,25 @@ void GameScreen::CreateContentViews(UI::LinearLayout *parent) {
}
}
if (portrait) {
parent->Add(new Choice(ga->T("Play"), ImageID("I_PLAY")))->OnClick.Handle(this, &GameScreen::OnPlay);
}
}
void GameScreen::CreateSettingsViews(UI::LinearLayout *rightColumn) {
void GameScreen::CreateSettingsViews(UI::ViewGroup *rightColumn) {
using namespace UI;
auto di = GetI18NCategory(I18NCat::DIALOG);
auto ga = GetI18NCategory(I18NCat::GAME);
const bool fileTypeSupportCRC = FileTypeSupportsCRC(info_->fileType);
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL);
rightColumnItems->SetSpacing(0.0f);
rightColumn->Add(rightColumnItems);
if (!inGame_) {
if (!inGame_ && !portrait) {
rightColumnItems->Add(new Choice(ga->T("Play"), ImageID("I_PLAY")))->OnClick.Handle(this, &GameScreen::OnPlay);
}
@@ -317,7 +326,7 @@ void GameScreen::CreateSettingsViews(UI::LinearLayout *rightColumn) {
if (info_->hasConfig) {
// Only show the Game Settings button here if the game has a config. Always showing it
// is confusing since it'll just control the global settings.
Choice *btnGameSettings = rightColumnItems->Add(new Choice(ga->T("Game Settings")));
Choice *btnGameSettings = rightColumnItems->Add(new Choice(ga->T("Game Settings"), ImageID("I_GEAR")));
btnGameSettings->OnClick.Handle(this, &GameScreen::OnGameSettings);
if (inGame_)
btnGameSettings->SetEnabled(false);
+2 -3
View File
@@ -46,10 +46,9 @@ public:
const char *tag() const override { return "Game"; }
protected:
void CreateContentViews(UI::LinearLayout *parent) override;
void CreateSettingsViews(UI::LinearLayout *parent) override;
void CreateContentViews(UI::ViewGroup *parent) override;
void CreateSettingsViews(UI::ViewGroup *parent) override;
bool SettingsToTheRight() const override { return true; }
std::string_view GetTitle() const override;
private:
+8 -5
View File
@@ -42,7 +42,7 @@ CopyableText::CopyableText(ImageID imageID, std::string_view text, UI::LinearLay
});
}
TopBar::TopBar(const UIContext &ctx, bool usePortraitLayout, std::string_view title, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) {
TopBar::TopBar(const UIContext &ctx, TopBarFlags flags, std::string_view title, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams), flags_(flags) {
using namespace UI;
SetSpacing(10.0f);
if (!layoutParams) {
@@ -55,10 +55,6 @@ TopBar::TopBar(const UIContext &ctx, bool usePortraitLayout, std::string_view ti
backButton_ ->OnClick.Add([](UI::EventParams &e) {
e.bubbleResult = DR_BACK;
});
if (!usePortraitLayout) {
// Not really liking this..
// backButton_->SetText(dlg->T("Back"));
}
if (!title.empty()) {
TextView *titleView = Add(new TextView(title, ALIGN_VCENTER | FLAG_WRAP_TEXT, false, new LinearLayoutParams(1.0f, Gravity::G_VCENTER)));
@@ -67,6 +63,13 @@ TopBar::TopBar(const UIContext &ctx, bool usePortraitLayout, std::string_view ti
// If using HCENTER, to balance the centering, add a spacer on the right.
// Add(new Spacer(50.0f));
}
if (flags & TopBarFlags::ContextMenuButton) {
Choice *menuButton = Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)));
menuButton->OnClick.Add([this](UI::EventParams &e) {
this->OnContextMenuClick.Trigger(e);
});
}
}
SettingInfoMessage::SettingInfoMessage(int align, float cutOffY, UI::AnchorLayoutParams *lp)
+12 -1
View File
@@ -1,5 +1,6 @@
#pragma once
#include "Common/Common.h"
#include "Common/UI/View.h"
#include "UI/ViewGroup.h"
@@ -15,14 +16,24 @@ public:
CopyableText(ImageID imageID, std::string_view text, UI::LinearLayoutParams *layoutParams = nullptr);
};
enum class TopBarFlags {
Default = 0,
Portrait = 1,
ContextMenuButton = 2,
};
ENUM_CLASS_BITOPS(TopBarFlags);
class TopBar : public UI::LinearLayout {
public:
// The context is needed to get the theme for the background.
TopBar(const UIContext &ctx, bool usePortraitLayout, std::string_view title, UI::LayoutParams *layoutParams = nullptr);
TopBar(const UIContext &ctx, TopBarFlags flags, std::string_view title, UI::LayoutParams *layoutParams = nullptr);
UI::View *GetBackButton() const { return backButton_; }
UI::Event OnContextMenuClick;
private:
UI::Choice *backButton_ = nullptr;
TopBarFlags flags_ = TopBarFlags::Default;
};
class SettingInfoMessage : public UI::LinearLayout {
+23 -10
View File
@@ -1,6 +1,7 @@
#include "Common/UI/ScrollView.h"
#include "Common/Data/Text/I18n.h"
#include "UI/SimpleDialogScreen.h"
#include "Common/UI/PopupScreens.h"
#include "UI/MiscViews.h"
void UISimpleBaseDialogScreen::CreateViews() {
@@ -12,7 +13,7 @@ void UISimpleBaseDialogScreen::CreateViews() {
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
root_ = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
root_->Add(new TopBar(*screenManager()->getUIContext(), portrait, GetTitle()));
root_->Add(new TopBar(*screenManager()->getUIContext(), portrait ? TopBarFlags::Portrait : TopBarFlags::Default, GetTitle()));
if (canScroll) {
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
@@ -37,22 +38,34 @@ void UITwoPaneBaseDialogScreen::CreateViews() {
// Portrait layout is just a vertical stack.
ignoreBottomInset_ = true;
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
root->Add(new TopBar(*screenManager()->getUIContext(), portrait, GetTitle()));
TopBarFlags topBarFlags = TopBarFlags::Portrait;
if (flags_ & TwoPaneFlags::SettingsInContextMenu) {
topBarFlags |= TopBarFlags::ContextMenuButton;
}
TopBar *topBar = root->Add(new TopBar(*screenManager()->getUIContext(), topBarFlags, GetTitle()));
root->SetSpacing(0);
CreateContentViews(root);
ScrollView *settingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f, Margins(8)));
LinearLayout *settingsPane = new LinearLayout(ORIENT_VERTICAL);
settingsScroll->Add(settingsPane);
CreateSettingsViews(settingsPane);
root->Add(settingsScroll);
if (flags_ & TwoPaneFlags::SettingsInContextMenu) {
topBar->OnContextMenuClick.Add([this](UI::EventParams &e) {
this->screenManager()->push(new PopupCallbackScreen([this](UI::ViewGroup *parent) {
CreateSettingsViews(parent);
}, nullptr));
});
} else {
ScrollView *settingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f, Margins(8)));
LinearLayout *settingsPane = new LinearLayout(ORIENT_VERTICAL);
settingsScroll->Add(settingsPane);
CreateSettingsViews(settingsPane);
root->Add(settingsScroll);
}
root_ = root;
} else {
ignoreBottomInset_ = false;
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
std::string title(GetTitle());
root->Add(new TopBar(*screenManager()->getUIContext(), portrait, title));
root->Add(new TopBar(*screenManager()->getUIContext(), portrait ? TopBarFlags::Portrait : TopBarFlags::Default, title));
root->SetSpacing(0);
LinearLayout *columns = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
@@ -67,7 +80,7 @@ void UITwoPaneBaseDialogScreen::CreateViews() {
settingsPane->Add(new Choice(di->T("Back"), ImageID("I_NAVIGATE_BACK")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
settingsScroll->Add(settingsPane);
if (SettingsToTheRight()) {
if (flags_ & TwoPaneFlags::SettingsToTheRight) {
CreateContentViews(columns);
columns->Add(settingsScroll);
} else {
+11 -5
View File
@@ -24,25 +24,31 @@ private:
void CreateViews() override;
};
enum class TwoPaneFlags {
Default = 0,
SettingsToTheRight = 1,
SettingsInContextMenu = 2,
};
ENUM_CLASS_BITOPS(TwoPaneFlags);
// A two-pane version of the above, where settings are meant to go in the settings pane,
// and contents in the content pane. Will generate nice layouts for portrait and landscape.
// but with a consistent portrait-compatible back button and title.
// The settings pane is scrollable while the other is not.
class UITwoPaneBaseDialogScreen : public UIBaseDialogScreen {
public:
UITwoPaneBaseDialogScreen(const Path &gamePath = Path()) : UIBaseDialogScreen(gamePath) {
UITwoPaneBaseDialogScreen(const Path &gamePath, TwoPaneFlags flags) : UIBaseDialogScreen(gamePath), flags_(flags) {
// We need to check CanScroll before we know whether to ignore
// bottom inset. Can't do that here, we do it in CreateViews
}
// Override this, don't override CreateViews. And don't touch root_ directly.
virtual void CreateSettingsViews(UI::LinearLayout *parent) = 0;
virtual void CreateContentViews(UI::LinearLayout *parent) = 0;
virtual void CreateSettingsViews(UI::ViewGroup *parent) = 0;
virtual void CreateContentViews(UI::ViewGroup *parent) = 0;
virtual std::string_view GetTitle() const { return ""; }
virtual float SettingsWidth() const { return 350.0f; }
virtual bool SettingsToTheRight() const { return false; }
private:
void CreateViews() override;
TwoPaneFlags flags_ = TwoPaneFlags::Default;
};
+2 -2
View File
@@ -83,12 +83,12 @@ std::string_view TiltAnalogSettingsScreen::GetTitle() const {
return co->T("Tilt control setup");
}
void TiltAnalogSettingsScreen::CreateContentViews(UI::LinearLayout *parent) {
void TiltAnalogSettingsScreen::CreateContentViews(UI::ViewGroup *parent) {
using namespace UI;
CreateCalibrationView(parent, new LinearLayoutParams(300.0f, 300.0f, 1.0f, Gravity::G_CENTER));
}
void TiltAnalogSettingsScreen::CreateSettingsViews(UI::LinearLayout *settings) {
void TiltAnalogSettingsScreen::CreateSettingsViews(UI::ViewGroup *settings) {
using namespace UI;
auto co = GetI18NCategory(I18NCat::CONTROLS);
+3 -3
View File
@@ -26,10 +26,10 @@ class GamepadView;
class TiltAnalogSettingsScreen : public UITwoPaneBaseDialogScreen {
public:
TiltAnalogSettingsScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath) {}
TiltAnalogSettingsScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::Default) {}
void CreateSettingsViews(UI::LinearLayout *parent) override;
void CreateContentViews(UI::LinearLayout *parent) override;
void CreateSettingsViews(UI::ViewGroup *parent) override;
void CreateContentViews(UI::ViewGroup*parent) override;
std::string_view GetTitle() const override;
void update() override;