Handle inset adjustements on the C++ side, handle them better in the UI.

This commit is contained in:
Henrik Rydgård
2026-03-14 17:06:23 +01:00
parent 13698f81fb
commit 75453632f9
32 changed files with 210 additions and 84 deletions
+36 -4
View File
@@ -141,15 +141,46 @@ Bounds UIContext::GetScissorBounds() {
return bounds_;
}
Bounds UIContext::GetLayoutBounds(bool ignoreBottomInset) const {
Bounds bounds = GetBounds();
Bounds UIContext::GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode) const {
float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);
float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT);
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM);
if (ignoreBottomInset) {
switch (layoutMode) {
case ViewLayoutMode::ApplyInsets:
// Nothing to do
break;
case ViewLayoutMode::IgnoreInsets:
left = 0.0f;
top = 0.0f;
right = 0.0f;
bottom = 0.0f;
break;
case ViewLayoutMode::IgnoreBottomInset:
bottom = 0.0f;
break;
}
if (immersiveMode) {
if (left > 0 && right > 0) {
// Navigation bar is available, so insets leave space for it
// even if it's hidden.
int smallestNonZero = std::min(right, left);
left = smallestNonZero;
right = smallestNonZero;
} else {
int sideWidth = std::max(left, right);
left = sideWidth;
right = sideWidth;
}
} else {
if ((left > 0) != (right > 0)) {
// Only one side has a cutout (surely the camera, which is usually smaller than the nav bar), so use the larger of the two for both sides.
int sideWidth = std::max(left, right);
left = sideWidth;
right = sideWidth;
}
}
// Note that we ignore bottom here, to let lists etc. extend to the bottom of the screen.
@@ -157,6 +188,7 @@ Bounds UIContext::GetLayoutBounds(bool ignoreBottomInset) const {
// touch things below the safe inset.
// Adjust left edge to compensate for cutouts (notches) if any.
Bounds bounds = GetBounds();
bounds.x += left;
bounds.w -= (left + right);
bounds.y += top;
+3 -1
View File
@@ -56,6 +56,8 @@ struct AtlasData {
typedef std::function<AtlasData(Draw::DrawContext *, AtlasChoice, float dpiScale, bool invalidate)> UIAtlasProviderFunc;
enum class ViewLayoutMode;
class UIContext {
public:
UIContext();
@@ -113,7 +115,7 @@ public:
// in dps, like dp_xres and dp_yres
void SetBounds(const Bounds &b) { bounds_ = b; }
const Bounds &GetBounds() const { return bounds_; }
Bounds GetLayoutBounds(bool ignoreBottomInset) const;
Bounds GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode) const;
Draw::DrawContext *GetDrawContext() const { return draw_; }
const UI::Theme &GetTheme() const {
return *theme;
+21 -11
View File
@@ -17,21 +17,31 @@
namespace UI {
static void TextToImage(std::string_view buttonText, ImageID *image) {
auto di = GetI18NCategory(I18NCat::DIALOG);
if (buttonText == di->T("Delete") || buttonText == di->T("Move to trash")) {
*image = ImageID("I_TRASHCAN");
} else if (buttonText == di->T("Back")) {
*image = ImageID("I_NAVIGATE_BACK");
} else if (buttonText == di->T("Add")) {
*image = ImageID("I_PLUS");
} else if (buttonText == di->T("OK")) {
*image = ImageID("I_CHECKMARK");
} else if (buttonText == di->T("Cancel")) {
*image = ImageID("I_NAVIGATE_BACK");
} else if (buttonText == di->T("Exit")) {
*image = ImageID("I_EXIT");
}
}
PopupScreen::PopupScreen(std::string_view title, std::string_view button1, std::string_view button2)
: title_(title), button1_(button1), button2_(button2) {
auto di = GetI18NCategory(I18NCat::DIALOG);
// Auto-assign images. A bit hack to have this here.
if (button1 == di->T("Delete") || button1 == di->T("Move to trash")) {
button1Image_ = ImageID("I_TRASHCAN");
} else if (button1 == di->T("Back")) {
button1Image_ = ImageID("I_NAVIGATE_BACK");
} else if (button1 == di->T("Add")) {
button1Image_ = ImageID("I_PLUS");
} else if (button1 == di->T("OK")) {
button1Image_ = ImageID("I_CHECKMARK");
if (!button1.empty()) {
TextToImage(button1, &button1Image_);
}
if (button2 == di->T("Cancel")) {
button2Image_ = ImageID("I_NAVIGATE_BACK");
if (!button2.empty()) {
TextToImage(button2, &button2Image_);
}
alpha_ = 0.0f; // inherited
+2 -2
View File
@@ -131,8 +131,8 @@ bool IsFocusMovementEnabled() {
return focusMovementEnabled;
}
void LayoutViewHierarchy(const UIContext &dc, const UI::Margins &rootMargins, ViewGroup *root, bool ignoreInsets, bool ignoreBottomInset) {
Bounds rootBounds = ignoreInsets ? dc.GetBounds() : dc.GetLayoutBounds(ignoreBottomInset);
void LayoutViewHierarchy(const UIContext &dc, const UI::Margins &rootMargins, ViewGroup *root, ViewLayoutMode layoutMode, bool immersiveMode) {
Bounds rootBounds = dc.GetLayoutBounds(layoutMode, immersiveMode);
MeasureSpec horiz(EXACTLY, rootBounds.w - (rootMargins.left + rootMargins.right));
MeasureSpec vert(EXACTLY, rootBounds.h - (rootMargins.top + rootMargins.bottom));
+1 -1
View File
@@ -24,7 +24,7 @@ DialogResult DispatchEvents();
class ViewGroup;
void LayoutViewHierarchy(const UIContext &dc, const UI::Margins &rootMargins, UI::ViewGroup *root, bool ignoreInsets, bool ignoreBottomInset);
void LayoutViewHierarchy(const UIContext &dc, const UI::Margins &rootMargins, UI::ViewGroup *root, ViewLayoutMode layoutMode, bool immersiveMode);
DialogResult UpdateViewHierarchy(ViewGroup *root);
enum class KeyEventResult {
+6
View File
@@ -70,6 +70,12 @@ enum class ScreenRenderRole {
};
ENUM_CLASS_BITOPS(ScreenRenderRole);
enum class ViewLayoutMode {
ApplyInsets = 0, // For gameplay, option #1
IgnoreInsets, // For gameplay, option #2
IgnoreBottomInset,
};
class Screen {
public:
Screen() = default;
+2 -2
View File
@@ -294,8 +294,8 @@ void ScrollView::Draw(UIContext &dc) {
dc.DrawRectDropShadow(shadowBounds, radius, fade);
}
// Same at the bottom.
const float y2 = dc.GetLayoutBounds(false).y2();
// Same at the bottom. (we check against the common UI layout mode)
const float y2 = dc.GetLayoutBounds(ViewLayoutMode::IgnoreBottomInset, false).y2();
if (shadows_ && bounds_.y2() < y2 && orientation_ == ORIENT_VERTICAL) {
float radius = 20.0f;
+3 -3
View File
@@ -55,7 +55,7 @@ void UIScreen::DoRecreateViews() {
// Update layout and refocus so things scroll into view.
// This is for resizing down, when focused on something now offscreen.
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), RootMargins(), root_, ignoreInsets_, ignoreBottomInset_);
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), RootMargins(), root_, LayoutMode(), UseImmersiveMode());
UI::View *focused = UI::GetFocusedView();
if (focused) {
root_->SubviewFocused(focused);
@@ -201,7 +201,7 @@ void UIScreen::deviceRestored(Draw::DrawContext *draw) {
}
Bounds UIScreen::GetLayoutBounds(UIContext &dc) const {
return dc.GetLayoutBounds(ignoreBottomInset_);
return dc.GetLayoutBounds(LayoutMode(), UseImmersiveMode());
}
ScreenRenderFlags UIScreen::render(ScreenRenderMode mode) {
@@ -209,7 +209,7 @@ ScreenRenderFlags UIScreen::render(ScreenRenderMode mode) {
UIContext &uiContext = *screenManager()->getUIContext();
if (root_) {
UI::LayoutViewHierarchy(uiContext, RootMargins(), root_, ignoreInsets_, ignoreBottomInset_);
UI::LayoutViewHierarchy(uiContext, RootMargins(), root_, LayoutMode(), UseImmersiveMode());
}
uiContext.PushTransform({translation_, scale_, alpha_});
+4 -2
View File
@@ -10,6 +10,8 @@
using namespace Lin;
enum class ViewLayoutMode;
class I18NCategory;
namespace Draw {
class DrawContext;
@@ -67,13 +69,13 @@ protected:
void RecreateViews() override { recreateViews_ = true; }
DeviceOrientation GetDeviceOrientation() const;
bool IsOnTop() const;
virtual ViewLayoutMode LayoutMode() const { return ViewLayoutMode::ApplyInsets; }
virtual bool UseImmersiveMode() const { return false; }
UI::ViewGroup *root_ = nullptr;
Vec3 translation_ = Vec3(0.0f);
Vec3 scale_ = Vec3(1.0f);
float alpha_ = 1.0f;
bool ignoreInsets_ = false;
bool ignoreBottomInset_ = false;
bool ignoreInput_ = false;
protected:
+19 -16
View File
@@ -54,7 +54,7 @@ void SetOverrideScreenFrame(const Bounds *bounds) {
}
}
FRect GetScreenFrame(bool ignoreInsets, float pixelWidth, float pixelHeight) {
FRect GetScreenFrame(bool ignoreScreenInsets, float pixelWidth, float pixelHeight) {
FRect rc = FRect{
0.0f,
0.0f,
@@ -62,21 +62,7 @@ FRect GetScreenFrame(bool ignoreInsets, float pixelWidth, float pixelHeight) {
pixelHeight,
};
const bool applyInset = !ignoreInsets;
if (applyInset) {
// Remove the DPI scale to get back to pixels.
float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_display.dpi_scale_x;
float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_display.dpi_scale_x;
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_display.dpi_scale_y;
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_display.dpi_scale_y;
// Adjust left edge to compensate for cutouts (notches) if any.
rc.x += left;
rc.w -= (left + right);
rc.y += top;
rc.h -= (top + bottom);
}
const bool applyInset = !ignoreScreenInsets;
if (g_overrideScreenBounds) {
// Set rectangle to match central node. Here we ignore bIgnoreScreenInsets.
@@ -84,6 +70,23 @@ FRect GetScreenFrame(bool ignoreInsets, float pixelWidth, float pixelHeight) {
rc.y = g_screenBounds.y;
rc.w = g_screenBounds.w;
rc.h = g_screenBounds.h;
} else if (applyInset) {
// Remove the DPI scale to get back to pixels.
float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_display.dpi_scale_x;
float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_display.dpi_scale_x;
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_display.dpi_scale_y;
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_display.dpi_scale_y;
// NOTE: Similarly to what we do in UI, we disregard any bottom inset when in landscape mode.
if (g_display.GetDeviceOrientation() == DeviceOrientation::Landscape) {
bottom = 0.0f;
}
// Adjust left edge to compensate for cutouts (notches) if any.
rc.x += left;
rc.w -= (left + right);
rc.y += top;
rc.h -= (top + bottom);
}
return rc;
+28
View File
@@ -0,0 +1,28 @@
#include "UI/BaseScreens.h"
#include "Core/Config.h"
ViewLayoutMode UIBaseScreen::LayoutMode() const {
return ViewLayoutMode::IgnoreBottomInset;
}
bool UIBaseScreen::UseImmersiveMode() const {
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
if (!portrait && config.bImmersiveMode) {
return true;
}
return false;
}
ViewLayoutMode UIBaseDialogScreen::LayoutMode() const {
return ViewLayoutMode::IgnoreBottomInset;
}
bool UIBaseDialogScreen::UseImmersiveMode() const {
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
if (!portrait && config.bImmersiveMode) {
return true;
}
return false;
}
+5
View File
@@ -8,6 +8,8 @@
class UIBaseScreen : public UIScreen {
public:
UIBaseScreen() : UIScreen() {}
ViewLayoutMode LayoutMode() const override;
bool UseImmersiveMode() const override;
protected:
void sendMessage(UIMessage message, const char *value) override;
};
@@ -17,6 +19,9 @@ public:
UIBaseDialogScreen() : UIDialogScreen(), gamePath_() {}
explicit UIBaseDialogScreen(const Path &gamePath) : UIDialogScreen(), gamePath_(gamePath) {}
protected:
ViewLayoutMode LayoutMode() const override;
bool UseImmersiveMode() const override;
void sendMessage(UIMessage message, const char *value) override;
void AddStandardBack(UI::ViewGroup *parent);
Path gamePath_;
+1 -1
View File
@@ -1025,7 +1025,7 @@ void VisualMappingScreen::MapNext(bool successive) {
HandleKeyMapping(mapping);
}, I18NCat::KEYMAPPING);
Bounds bounds = screenManager()->getUIContext()->GetLayoutBounds(false);
Bounds bounds = screenManager()->getUIContext()->GetLayoutBounds(LayoutMode(), false);
dialog->SetPopupOffset(psp_->GetPopupOffset() * bounds.h);
dialog->SetDelay(successive ? 0.5f : 0.1f);
screenManager()->push(dialog);
+1 -1
View File
@@ -142,7 +142,7 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) {
array[i] = (0x01 == ((g_Config.CustomButton[id_].key >> i) & 0x01));
// TODO: Less hacky layout work
const Bounds layoutBounds = screenManager()->getUIContext()->GetLayoutBounds(false);
const Bounds layoutBounds = GetLayoutBounds(*screenManager()->getUIContext());
leftColumn->Add(new ButtonPreview(g_Config.iTouchButtonStyle == 0 ? customKeyShapes[cfg->shape].i : customKeyShapes[cfg->shape].l,
customKeyImages[cfg->image].i, customKeyImages[cfg->image].r, customKeyShapes[cfg->shape].f, customKeyShapes[cfg->shape].r, layoutBounds.x + 62, layoutBounds.y + 102));
+4 -3
View File
@@ -220,13 +220,14 @@ void DrawFramebufferList(UIContext *ctx, GPUDebugInterface *gpu, const Bounds &b
}
void DrawControlMapperOverlay(UIContext *ctx, const Bounds &bounds, const ControlMapper &controlMapper) {
DrawControlDebug(ctx, controlMapper, ctx->GetLayoutBounds(false));
DrawControlDebug(ctx, controlMapper, ctx->GetLayoutBounds(ViewLayoutMode::ApplyInsets, false));
}
void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay) {
bool inGame = GetUIState() == UISTATE_INGAME;
const Bounds layoutBounds = ctx->GetLayoutBounds(false);
const Bounds layoutBounds = ctx->GetLayoutBounds(ViewLayoutMode::ApplyInsets, false);
switch (overlay) {
case DebugOverlay::DEBUG_STATS:
if (inGame)
@@ -256,7 +257,7 @@ void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay
#endif
case DebugOverlay::FRAMEBUFFER_LIST:
if (inGame)
DrawFramebufferList(ctx, gpu, bounds);
DrawFramebufferList(ctx, gpu, layoutBounds);
break;
default:
break;
+4
View File
@@ -179,6 +179,10 @@ public:
const char *tag() const override { return "TouchTest"; }
protected:
ViewLayoutMode LayoutMode() const override {
return ViewLayoutMode::ApplyInsets;
}
struct TrackedTouch {
int id;
float x;
+8 -4
View File
@@ -282,11 +282,15 @@ void DisplayLayoutScreen::CreateViews() {
supportsInsets = true;
#endif
// Hide insets option if no insets, or OS too old.
float insetLeft = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);
float insetRight = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT);
float insetTop = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
float insetBottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM);
if (supportsInsets && (
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f ||
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f ||
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f ||
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) {
insetLeft != 0.0f ||
insetTop != 0.0f ||
insetRight != 0.0f ||
insetBottom != 0.0f) && (insetLeft != insetTop || insetRight != insetBottom)) {
rightColumn->Add(new CheckBox(&config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering")));
}
+6 -1
View File
@@ -1268,6 +1268,7 @@ void EmuScreen::CreateViews() {
TouchControlConfig &touch = g_Config.GetTouchControlsConfig(deviceOrientation);
const Bounds &bounds = GetLayoutBounds(*screenManager()->getUIContext());
InitPadLayout(&touch, deviceOrientation, bounds.w, bounds.h);
root_ = CreatePadLayout(touch, bounds.w, bounds.h, &pauseTrigger_, &g_controlMapper);
@@ -1429,6 +1430,10 @@ void EmuScreen::OnChat(UI::EventParams &params) {
// To avoid including proAdhoc.h, which includes a lot of stuff.
int GetChatMessageCount();
ViewLayoutMode EmuScreen::LayoutMode() const {
return ViewLayoutMode::ApplyInsets;
}
void EmuScreen::update() {
using namespace UI;
@@ -1963,7 +1968,7 @@ void EmuScreen::renderUI() {
ctx->Begin();
if (root_) {
UI::LayoutViewHierarchy(*ctx, RootMargins(), root_, false, false);
UI::LayoutViewHierarchy(*ctx, RootMargins(), root_, LayoutMode(), UseImmersiveMode());
root_->Draw(*ctx);
}
+1
View File
@@ -77,6 +77,7 @@ protected:
void OnVKeyAnalog(VirtKey virtualKeyCode, float value) override;
void UpdatePSPButtons(uint32_t buttonMask, uint32_t changedMask) override;
void SetPSPAnalog(int rotation, int stick, float x, float y) override;
ViewLayoutMode LayoutMode() const override;
private:
void CreateViews() override;
-1
View File
@@ -235,7 +235,6 @@ static_assert(Draw::SEM_TEXCOORD0 == 3, "Semantic shader hardcoded in glsl above
GPUDriverTestScreen::GPUDriverTestScreen() {
using namespace Draw;
ignoreBottomInset_ = false;
}
GPUDriverTestScreen::~GPUDriverTestScreen() {
-1
View File
@@ -1217,7 +1217,6 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) {
// Hide Immersive Mode on pre-kitkat Android
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) {
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
// Let's reuse the Fullscreen translation string from desktop.
systemSettings->Add(new CheckBox(&config.bImmersiveMode, sy->T("Hide navigation bar")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
}
#endif
-1
View File
@@ -1150,7 +1150,6 @@ void GameBrowser::OnHomebrewStore(UI::EventParams &e) {
MainScreen::MainScreen() {
g_BackgroundAudio.SetGame(Path());
ignoreBottomInset_ = true;
}
MainScreen::~MainScreen() {
+2
View File
@@ -137,6 +137,8 @@ public:
bool key(const KeyInput &touch) override;
protected:
ViewLayoutMode LayoutMode() const override { return ViewLayoutMode::IgnoreBottomInset; }
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);
-2
View File
@@ -506,8 +506,6 @@ std::string_view CreditsScreen::GetTitle() const {
void CreditsScreen::CreateDialogViews(UI::ViewGroup *parent) {
using namespace UI;
ignoreBottomInset_ = false;
auto di = GetI18NCategory(I18NCat::DIALOG);
auto cr = GetI18NCategory(I18NCat::PSPCREDITS);
auto mm = GetI18NCategory(I18NCat::MAINMENU);
+5
View File
@@ -109,6 +109,10 @@ public:
const char *tag() const override { return "Logo"; }
protected:
ViewLayoutMode LayoutMode() const override { return ViewLayoutMode::ApplyInsets; }
bool UseImmersiveMode() const override { return true; }
private:
void Next();
int frames_ = 0;
@@ -123,6 +127,7 @@ public:
void update() override;
protected:
ViewLayoutMode LayoutMode() const override { return ViewLayoutMode::ApplyInsets; }
std::string_view GetTitle() const override;
void CreateDialogViews(UI::ViewGroup *parent) override;
+5
View File
@@ -425,6 +425,11 @@ void OSDOverlayScreen::update() {
DoRecreateViews();
}
ViewLayoutMode OSDOverlayScreen::LayoutMode() const {
// Need the full insets to avoid notifications appearing out of any bounds.
return ViewLayoutMode::ApplyInsets;
}
void NoticeView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const {
float layoutWidth = layoutParams_->width;
if (layoutWidth < 0) {
+2 -3
View File
@@ -36,9 +36,6 @@ private:
class OSDOverlayScreen : public UIScreen {
public:
OSDOverlayScreen() {
ignoreInsets_ = false;
}
const char *tag() const override { return "OSDOverlayScreen"; }
bool UnsyncTouch(const TouchInput &touch) override;
@@ -47,6 +44,8 @@ public:
void DrawForeground(UIContext &ui) override;
void update() override;
protected:
ViewLayoutMode LayoutMode() const override;
private:
OnScreenMessagesView *osmView_ = nullptr;
};
+18 -8
View File
@@ -4,12 +4,13 @@
#include "Common/UI/PopupScreens.h"
#include "UI/MiscViews.h"
ViewLayoutMode UISimpleBaseDialogScreen::LayoutMode() const {
return (flags_ & SimpleDialogFlags::ContentsCanScroll) ? ViewLayoutMode::IgnoreBottomInset : ViewLayoutMode::ApplyInsets;
}
void UISimpleBaseDialogScreen::CreateViews() {
using namespace UI;
const bool canScroll = flags_ & SimpleDialogFlags::ContentsCanScroll;
ignoreBottomInset_ = canScroll;
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
root_ = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
@@ -29,7 +30,7 @@ void UISimpleBaseDialogScreen::CreateViews() {
});
}
if (canScroll) {
if (flags_ & SimpleDialogFlags::ContentsCanScroll) {
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
LinearLayout *contents = new LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(Margins(0, 0, 8, 0)));
contents->SetSpacing(0);
@@ -41,6 +42,19 @@ void UISimpleBaseDialogScreen::CreateViews() {
}
}
ViewLayoutMode UITwoPaneBaseDialogScreen::LayoutMode() const {
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
if (portrait) {
if (flags_ & TwoPaneFlags::SettingsCanScroll) {
return ViewLayoutMode::IgnoreBottomInset;
} else {
return ViewLayoutMode::ApplyInsets;
}
} else {
return ViewLayoutMode::ApplyInsets;
}
}
void UITwoPaneBaseDialogScreen::CreateViews() {
using namespace UI;
@@ -72,9 +86,6 @@ void UITwoPaneBaseDialogScreen::CreateViews() {
if (portrait) {
// Portrait layout is just a vertical stack.
if (flags_ & TwoPaneFlags::SettingsCanScroll) {
ignoreBottomInset_ = true;
}
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
TopBarFlags topBarFlags = TopBarFlags::Portrait;
@@ -114,7 +125,6 @@ void UITwoPaneBaseDialogScreen::CreateViews() {
}
root_ = root;
} else {
ignoreBottomInset_ = false;
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
std::string title(GetTitle());
TopBarFlags topBarFlags = portrait ? TopBarFlags::Portrait : TopBarFlags::Default;
+6
View File
@@ -26,6 +26,9 @@ public:
virtual void CreateContextMenu(UI::ViewGroup *parent) {} // only called if CustomContextMenu is set in flags.
virtual std::string_view GetTitle() const { return ""; }
protected:
ViewLayoutMode LayoutMode() const override;
private:
void CreateViews() override;
SimpleDialogFlags flags_;
@@ -61,6 +64,9 @@ public:
virtual std::string_view GetTitle() const { return ""; }
virtual float SettingsWidth() const { return 350.0f; }
protected:
ViewLayoutMode LayoutMode() const override;
private:
void CreateViews() override;
TwoPaneFlags flags_ = TwoPaneFlags::Default;
+1 -3
View File
@@ -30,9 +30,7 @@ ENUM_CLASS_BITOPS(TabFlags);
class UITabbedBaseDialogScreen : public UIBaseDialogScreen {
public:
UITabbedBaseDialogScreen(const Path &gamePath, TabDialogFlags flags = TabDialogFlags::Default) : UIBaseDialogScreen(gamePath), flags_(flags) {
ignoreBottomInset_ = true;
}
UITabbedBaseDialogScreen(const Path &gamePath, TabDialogFlags flags = TabDialogFlags::Default) : UIBaseDialogScreen(gamePath), flags_(flags) {}
void AddTab(const char *tag, std::string_view title, ImageID imageId, std::function<void(UI::LinearLayout *)> createCallback, TabFlags flags = TabFlags::Default);
void AddTab(const char *tag, std::string_view title, std::function<void(UI::LinearLayout *)> createCallback, TabFlags flags = TabFlags::Default) {
+16
View File
@@ -406,11 +406,27 @@ float System_GetPropertyFloat(SystemProperty prop) {
return ScreenRefreshRateHz();
case SYSPROP_DISPLAY_DPI:
return ScreenDPI();
#if 0
// Simulate something like Android landscape mode for testing
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
return 45.0f;
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
return 100.0f;
case SYSPROP_DISPLAY_SAFE_INSET_TOP:
return 0.0f;
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
return 80.0f;
#else
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
return 0.0f;
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
return 0.0f;
case SYSPROP_DISPLAY_SAFE_INSET_TOP:
return 0.0f;
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
return 0.0f;
#endif
default:
return -1;
}
@@ -919,19 +919,6 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
int right = insets.right;
int top = insets.top;
int bottom = insets.bottom;
// Log.w(TAG, "updateInsets: " + left + ", " + right + ", " + top + ", " + bottom);
// Hack to make things symmetrical in landscape. Needed on Poco F1, for example.
if (orientation == Configuration.ORIENTATION_LANDSCAPE && useImmersive()) {
if (left > 0 && right > 0) {
int smallestNonZero = Math.min(right, left);
// Log.i(TAG, "Both left and right insets but not equal: " + left + " != " + right + " : Equalizing to " + smallest);
left = smallestNonZero;
right = smallestNonZero;
}
}
NativeApp.sendMessageFromJava("safe_insets", left + ":" + right + ":" + top + ":" + bottom);
}