Various inset and margin fixes and improvements

This commit is contained in:
Henrik Rydgård
2025-10-28 12:39:23 +01:00
parent 138be54f6a
commit b660dcee2b
9 changed files with 78 additions and 52 deletions
+7
View File
@@ -31,6 +31,13 @@ enum Orientation {
ORIENT_VERTICAL,
};
// Workaround for X header, ugh.
#undef Opposite
inline constexpr Orientation Opposite(Orientation o) {
return (o == ORIENT_HORIZONTAL) ? ORIENT_VERTICAL : ORIENT_HORIZONTAL;
}
// Resolved bounds on screen after layout.
struct Bounds {
Bounds() : x(0.0f), y(0.0f), w(0.0f), h(0.0f) {}
+6 -3
View File
@@ -143,14 +143,17 @@ Bounds UIContext::GetLayoutBounds() 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);
// float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM);
// Note that we ignore bottom here, to let lists etc. extend to the bottom of the screen.
// However, we will add the same space to the bottom of scrolled lists, so that you don't have to
// touch things below the safe inset.
// Adjust left edge to compensate for cutouts (notches) if any.
bounds.x += left;
bounds.w -= (left + right);
bounds.y += top;
bounds.h -= (top + bottom);
bounds.h -= top;
return bounds;
}
+27 -16
View File
@@ -1,4 +1,6 @@
#include <algorithm>
#include "Common/System/System.h"
#include "Common/System/Display.h"
#include "Common/UI/Context.h"
#include "Common/UI/ScrollView.h"
#include "Common/Data/Text/I18n.h"
@@ -208,12 +210,28 @@ bool ScrollView::Touch(const TouchInput &input) {
}
}
float ScrollView::ChildSize() const {
float extraSpace = 0.0f;
if (orientation_ == ORIENT_VERTICAL) {
if (bounds_.y2() >= g_display.dp_yres - 1) {
extraSpace = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM);
}
}
if (views_.empty()) {
// Avoid division by zero. This shouldn't happen, anyway.
return 1.0f;
}
return std::max(0.01f, views_[0]->GetBounds().GetSize(orientation_) + extraSpace);
}
ScrollView::Bob ScrollView::ComputeBob() const {
Bob bob{};
if (views_.empty()) {
return bob;
}
float childHeight = std::max(0.01f, views_[0]->GetBounds().h);
const float childHeight = ChildSize();
float scrollMax = std::max(0.0f, childHeight - bounds_.h);
float ratio = bounds_.h / childHeight;
@@ -404,9 +422,9 @@ float ScrollView::HardClampedScrollPos(float pos) const {
if (!views_.size() || bounds_.h == 0.0f) {
return 0.0f;
}
float childSize = orientation_ == ORIENT_VERTICAL ? views_[0]->GetBounds().h : views_[0]->GetBounds().w;
float containerSize = (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w);
float scrollMax = std::max(0.0f, childSize - containerSize);
const float childSize = ChildSize();
const float containerSize = bounds_.GetSize(orientation_);
const float scrollMax = std::max(0.0f, childSize - containerSize);
return Clamp(pos, 0.0f, scrollMax);
}
@@ -415,8 +433,8 @@ float ScrollView::ClampedScrollPos(float pos) {
return 0.0f;
}
float childSize = orientation_ == ORIENT_VERTICAL ? views_[0]->GetBounds().h : views_[0]->GetBounds().w;
float containerSize = (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w);
float childSize = ChildSize();
float containerSize = bounds_.GetSize(orientation_);
float scrollMax = std::max(0.0f, childSize - containerSize);
Gesture gesture = orientation_ == ORIENT_VERTICAL ? GESTURE_DRAG_VERTICAL : GESTURE_DRAG_HORIZONTAL;
@@ -448,8 +466,8 @@ float ScrollView::ClampedScrollPos(float pos) {
}
void ScrollView::ScrollToBottom() {
float childHeight = views_[0]->GetBounds().h;
float scrollMax = std::max(0.0f, childHeight - bounds_.h);
const float childSize = ChildSize();
const float scrollMax = std::max(0.0f, childSize - bounds_.GetSize(orientation_));
scrollPos_ = scrollMax;
scrollTarget_ = scrollMax;
}
@@ -457,14 +475,7 @@ void ScrollView::ScrollToBottom() {
bool ScrollView::CanScroll() const {
if (!views_.size())
return false;
switch (orientation_) {
case ORIENT_VERTICAL:
return views_[0]->GetBounds().h > bounds_.h;
case ORIENT_HORIZONTAL:
return views_[0]->GetBounds().w > bounds_.w;
default:
return false;
}
return ChildSize() > bounds_.GetSize(orientation_);
}
void ScrollView::GetLastScrollPosition(float &x, float &y) {
+1
View File
@@ -47,6 +47,7 @@ public:
NeighborResult FindScrollNeighbor(View *view, const Point2D &target, FocusDirection direction, NeighborResult best) override;
private:
float ChildSize() const; // in the scrolled direction
float HardClampedScrollPos(float pos) const;
// TODO: Don't adjust pull_ within this!
-4
View File
@@ -184,10 +184,6 @@ enum class BorderStyle {
ITEM_DOWN_BG,
};
inline Orientation Opposite(Orientation o) {
if (o == ORIENT_HORIZONTAL) return ORIENT_VERTICAL; else return ORIENT_HORIZONTAL;
}
inline FocusDirection Opposite(FocusDirection d) {
switch (d) {
case FOCUS_UP: return FOCUS_DOWN;
+2 -2
View File
@@ -1296,11 +1296,11 @@ void MainScreen::CreateViews() {
}
if (vertical) {
LinearLayout *header = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(0, 16, 0, 8)));
LinearLayout *header = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(8, 8, 8, 16)));
header->SetSpacing(5.0f);
header->Add(CreateLogoView(true, new LinearLayoutParams(WRAP_CONTENT, 80.0f, false)));
LinearLayout *buttonGroup = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f, UI::Gravity::G_VCENTER, UI::Margins(0,0,8,0)));
LinearLayout *buttonGroup = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f, UI::Gravity::G_VCENTER));
CreateMainButtons(buttonGroup, vertical);
header->Add(buttonGroup);
+7 -7
View File
@@ -927,7 +927,7 @@ public:
}
return true;
}
void Draw(UIContext &dc);
void Draw(UIContext &dc) override;
private:
Instant startTime_ = Instant::Now();
double dragYStart_ = -1.0;
@@ -974,24 +974,24 @@ void CreditsScreen::CreateViews() {
});
rightYOffset = 74;
}
left->Add(new Choice(cr->T("PPSSPP Forums"), ImageID("I_LINK_OUT")))->OnClick.Add([this](UI::EventParams &e) {
left->Add(new Choice(cr->T("PPSSPP Forums"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://forums.ppsspp.org");
});
left->Add(new Choice(cr->T("Discord"), ImageID("I_LOGO_DISCORD")))->OnClick.Add([this](UI::EventParams &e) {
left->Add(new Choice(cr->T("Discord"), ImageID("I_LOGO_DISCORD")))->OnClick.Add([](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://discord.gg/5NJB6dD");
});
left->Add(new Choice("www.ppsspp.org", ImageID("I_LINK_OUT")))->OnClick.Add([this](UI::EventParams &e) {
left->Add(new Choice("www.ppsspp.org", ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org");
});
right->Add(new Choice(cr->T("Privacy Policy"), ImageID("I_LINK_OUT")))->OnClick.Add([this](UI::EventParams &e) {
right->Add(new Choice(cr->T("Privacy Policy"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/privacy");
});
right->Add(new Choice(cr->T("@PPSSPP_emu"), ImageID("I_LOGO_X")))->OnClick.Add([this](UI::EventParams &e) {
right->Add(new Choice(cr->T("@PPSSPP_emu"), ImageID("I_LOGO_X")))->OnClick.Add([](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://x.com/PPSSPP_emu");
});
if (System_GetPropertyBool(SYSPROP_SUPPORTS_SHARE_TEXT)) {
right->Add(new Choice(cr->T("Share PPSSPP"), ImageID("I_SHARE")))->OnClick.Add([this](UI::EventParams &e) {
right->Add(new Choice(cr->T("Share PPSSPP"), ImageID("I_SHARE")))->OnClick.Add([](UI::EventParams &e) {
auto cr = GetI18NCategory(I18NCat::PSPCREDITS);
System_ShareText(cr->T("CheckOutPPSSPP", "Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/"));
});
+23 -16
View File
@@ -300,25 +300,32 @@ extern float g_safeInsetRight;
extern float g_safeInsetTop;
extern float g_safeInsetBottom;
static float BoostInset(float inset) {
if (inset > 0.0f) {
// If there's some inset, add a few pixels extra. Really needed on iPhone 12, at least.
inset += 4.0f;
}
return inset;
}
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
// we use 0.0f instead of safeAreaInsets.bottom because the bottom overlay isn't disturbing (for now)
g_safeInsetLeft = BoostInset(self.view.safeAreaInsets.left);
g_safeInsetRight = BoostInset(self.view.safeAreaInsets.right);
g_safeInsetTop = BoostInset(self.view.safeAreaInsets.top);
// TODO: In portrait mode, should probably use safeAreaInsets.bottom.
// However, in landscape mode, it's not really needed.
// g_safeInsetBottom = BoostInset(self.view.safeAreaInsets.bottom);
g_safeInsetBottom = 0.0f;
// Converts points to pixels.
CGFloat scale = UIScreen.mainScreen.scale;
float xInsetSum = self.view.safeAreaInsets.left + self.view.safeAreaInsets.right;
float yInsetSum = self.view.safeAreaInsets.top + self.view.safeAreaInsets.bottom;
// Only use the larger set of insets. The other set, we'll handle through layouts.
// Also, we'll treat the bottom inset differently: We'll add some space at the end of everything
// that scrolls so that when you're not at the bottom, we use the full vertical area,
// just looks better.
if (xInsetSum > yInsetSum) {
// Landscape mode insets are larger, use those.
g_safeInsetLeft = self.view.safeAreaInsets.left * scale;
g_safeInsetRight = self.view.safeAreaInsets.right * scale;
g_safeInsetTop = 0.0f;
g_safeInsetBottom = 0.0f;
} else {
// Portrait mode insets are larger, use those.
g_safeInsetLeft = 0.0f;
g_safeInsetRight = 0.0f;
g_safeInsetTop = self.view.safeAreaInsets.top * scale;
g_safeInsetBottom = self.view.safeAreaInsets.bottom * scale;
}
}
- (void)shareText:(NSString *)text {
+5 -4
View File
@@ -36,6 +36,7 @@
#include "Common/StringUtils.h"
#include "Common/Profiler/Profiler.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/System/Display.h"
#include "Core/Config.h"
#include "Common/Log.h"
#include "Common/Log/LogManager.h"
@@ -343,13 +344,13 @@ float System_GetPropertyFloat(SystemProperty prop) {
case SYSPROP_DISPLAY_REFRESH_RATE:
return 60.f;
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
return g_safeInsetLeft;
return g_safeInsetLeft * g_display.dpi_scale_x;
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
return g_safeInsetRight;
return g_safeInsetRight * g_display.dpi_scale_x;
case SYSPROP_DISPLAY_SAFE_INSET_TOP:
return g_safeInsetTop;
return g_safeInsetTop * g_display.dpi_scale_y;
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
return g_safeInsetBottom;
return g_safeInsetBottom * g_display.dpi_scale_y;
default:
return -1;
}