Merge pull request #23007 from hrydgard/more-ui-fixes

More UI fixes
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-11-09 11:59:40 +01:00
commit c6950d22ee
12 files changed
+64 -31

No files matched your search

+5
View File
@@ -200,6 +200,11 @@ enum SystemProperty {
// How far down the screen the side insets are needed (they're for something in a top corner), or -1.
SYSPROP_DISPLAY_SIDE_INSETS_BOTTOM,
SYSPROP_DISPLAY_HAS_CAMERA_CUTOUT,
// The navigation bar's insets, also while it's hidden (a swipe from the edge brings it back).
SYSPROP_DISPLAY_NAVBAR_INSET_LEFT,
SYSPROP_DISPLAY_NAVBAR_INSET_RIGHT,
SYSPROP_DISPLAY_NAVBAR_INSET_TOP,
SYSPROP_DISPLAY_NAVBAR_INSET_BOTTOM,
SYSPROP_DEVICE_TYPE,
SYSPROP_APP_GOLD, // To avoid having #ifdef GOLD other than in main.cpp and similar.
+13 -1
View File
@@ -146,7 +146,7 @@ Bounds UIContext::GetScissorBounds() {
return bounds_;
}
Bounds UIContext::GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode) const {
Bounds UIContext::GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode, bool reserveHiddenNavBar) 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);
@@ -205,6 +205,18 @@ Bounds UIContext::GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode)
}
}
if (reserveHiddenNavBar && layoutMode != ViewLayoutMode::IgnoreInsets) {
// Platforms without a navigation bar return -1, which leaves the insets alone.
if (layoutMode != ViewLayoutMode::IgnoreSideInsets) {
left = std::max(left, System_GetPropertyFloat(SYSPROP_DISPLAY_NAVBAR_INSET_LEFT));
right = std::max(right, System_GetPropertyFloat(SYSPROP_DISPLAY_NAVBAR_INSET_RIGHT));
}
top = std::max(top, System_GetPropertyFloat(SYSPROP_DISPLAY_NAVBAR_INSET_TOP));
if (layoutMode != ViewLayoutMode::IgnoreBottomInset) {
bottom = std::max(bottom, System_GetPropertyFloat(SYSPROP_DISPLAY_NAVBAR_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.
+2 -1
View File
@@ -118,7 +118,8 @@ public:
// in dps, like dp_xres and dp_yres
void SetBounds(const Bounds &b) { bounds_ = b; }
const Bounds &GetBounds() const { return bounds_; }
Bounds GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode) const;
// reserveHiddenNavBar keeps out of where the navigation bar comes back on a swipe, even while it's hidden.
Bounds GetLayoutBounds(ViewLayoutMode layoutMode, bool immersiveMode, bool reserveHiddenNavBar = false) const;
Draw::DrawContext *GetDrawContext() const { return draw_; }
const UI::Theme &GetTheme() const {
return *theme;
-1
View File
@@ -238,7 +238,6 @@ void PopupScreen::CreateViews() {
box_->Add(buttonRow);
}
box_->SetRoundCorners(RoundCorners::All);
// Rounds the top of the header and the bottom of the last view, to match the box.
box_->SetRoundCorners(RoundCorners::All);
}
+2 -2
View File
@@ -130,7 +130,7 @@ void UIScreen::deviceRestored(Draw::DrawContext *draw) {
}
Bounds UIScreen::GetLayoutBounds(UIContext &dc) const {
return dc.GetLayoutBounds(LayoutMode(), UseImmersiveMode());
return dc.GetLayoutBounds(LayoutMode(), UseImmersiveMode(), ReserveHiddenNavBar());
}
// On TVs and big monitors, controls out at the edges are hard to see and far apart. Grows with the
@@ -151,7 +151,7 @@ static float LargeScreenInset() {
Bounds UIScreen::GetContentBounds(const UIContext &dc) const {
const UI::Margins margins = RootMargins();
Bounds bounds = dc.GetLayoutBounds(LayoutMode(), UseImmersiveMode());
Bounds bounds = dc.GetLayoutBounds(LayoutMode(), UseImmersiveMode(), ReserveHiddenNavBar());
bounds.x += margins.left;
bounds.y += margins.top;
bounds.w -= margins.horiz();
+2
View File
@@ -69,6 +69,8 @@ protected:
bool IsOnTop() const;
virtual ViewLayoutMode LayoutMode() const { return ViewLayoutMode::ApplyInsets; }
virtual bool UseImmersiveMode() const { return false; }
// For screens with buttons near the edges: a swipe can bring back a hidden navigation bar over them.
virtual bool ReserveHiddenNavBar() const { return false; }
UI::ViewGroup *root_ = nullptr;
Vec3 translation_ = Vec3(0.0f);
+1
View File
@@ -853,6 +853,7 @@ void LinearLayout::Layout() {
// Applies rounding to the corners of the child views, based on their position in the layout and the orientation. Masked by the outerCorners.
// Ignores invisible views.
void LinearLayout::SetRoundCorners(RoundCorners outerCorners) {
roundCorners_ = outerCorners;
// Easy case first: There's spacing, just apply round corners to all subviews.
if (spacing_ > 0.0f) {
for (View *view : views_) {
+16 -22
View File
@@ -217,12 +217,12 @@ private:
};
AdhocServerCompactInfo::AdhocServerCompactInfo(const AdhocServerListEntry &entry, UI::LayoutParams *layoutParams)
: UI::LinearLayout(ORIENT_HORIZONTAL, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(5.0f, 0.0f))), entry_(entry) {
: UI::LinearLayout(ORIENT_HORIZONTAL, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)), entry_(entry) {
using namespace UI;
SetSpacing(5.0f);
LinearLayout *lines = Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(5, 5))));
LinearLayout *lines = Add(new LinearLayout(ORIENT_VERTICAL));
lines->SetSpacing(0.0f);
TextView *name = lines->Add(new TextView(entry.name));
@@ -234,10 +234,10 @@ AdhocServerCompactInfo::AdhocServerCompactInfo(const AdhocServerListEntry &entry
lines->Add(new TextView(secondLine))->SetTextSize(TextSize::Small)->SetWordWrap();
Add(new Spacer(0.0f, new LinearLayoutParams(1.0f, Margins(0.0f, 5.0f))));
Add(new Spacer(0.0f, new LinearLayoutParams(1.0f)));
if (entry.mode == AdhocDataMode::AemuPostoffice) {
TextView *relay = Add(new TextView(n->T("Relay"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(10.0))));
TextView *relay = Add(new TextView(n->T("Relay"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(0.0))));
}
Add(new Choice(ImageID("I_FILE_COPY"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)))->OnClick.Add([host = entry_.host](UI::EventParams &) {
@@ -245,12 +245,6 @@ AdhocServerCompactInfo::AdhocServerCompactInfo(const AdhocServerListEntry &entry
});
}
void AdhocServerCompactInfo::Draw(UIContext &dc) {
UI::LinearLayout::Draw(dc);
// Underline
dc.Draw()->DrawImageCenterTexel(dc.GetTheme().whiteImage, bounds_.x, bounds_.y2() - 2, bounds_.x2(), bounds_.y2(), dc.GetTheme().popupTitleStyle.fgColor);
}
static UI::View *CreateInfoItemWithButton(std::string_view text, ImageID buttonImage, std::function<void(UI::EventParams &)> onClick) {
using namespace UI;
LinearLayout *line = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(12, 0)));
@@ -372,22 +366,18 @@ void AdhocServerInfoScreen::CreatePopupContents(UI::ViewGroup *parent) {
auto di = GetI18NCategory(I18NCat::DIALOG);
auto ni = GetI18NCategory(I18NCat::NETWORKING);
Margins contentMargins(12, 0);
parent->Add(new AdhocServerCompactInfo(entry_, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, contentMargins)));
parent->Add(new Spacer(5.0f));
parent->Add(new AdhocServerCompactInfo(entry_, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
LinearLayout *content = new LinearLayout(ORIENT_VERTICAL);
content->SetSpacing(6.0f);
content->SetSpacing(8.0f);
if (!entry_.ip.empty()) {
content->Add(new InfoItem(entry_.ip, ""));
}
TextView *desc = content->Add(new TextView(entry_.description, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, contentMargins)));
desc->SetTextSize(TextSize::Small);
desc->SetWordWrap();
InfoItem *desc = content->Add(new InfoItem(entry_.description, "", new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
desc->SetRoundCorners();
LinearLayout *buttonStrip = content->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, contentMargins)));
LinearLayout *buttonStrip = content->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
buttonStrip->SetSpacing(8);
if (!entry_.web.empty() || !entry_.discord.empty()) {
if (!entry_.web.empty()) {
@@ -412,6 +402,8 @@ void AdhocServerInfoScreen::CreatePopupContents(UI::ViewGroup *parent) {
CreateAdhocServerGameList(content, games_, statusRequest_.get() ? true : false);
}
buttonStrip->SetRoundCorners();
scroll->Add(content);
parent->Add(scroll);
}
@@ -500,16 +492,17 @@ private:
};
AdhocServerRow::AdhocServerRow(std::string *editValue, const AdhocServerListEntry &entry, bool showDeleteButton, ScreenManager *screenManager, UI::LayoutParams *layoutParams)
: UI::LinearLayout(ORIENT_HORIZONTAL, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(5.0f, 0.0f))), value_(editValue), entry_(entry) {
: UI::LinearLayout(ORIENT_HORIZONTAL, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)), value_(editValue), entry_(entry) {
using namespace UI;
SetSpacing(5.0f);
SetPadding(Margins(10.0f, 2.0f, 0.0f, 2.0f));
// Show as radio button to make it really clear that selection actually is the choice.
int number = 0;
Add(new ImageView([editValue, host = entry.host]() { return host == *editValue ? ImageID("I_RADIO_SELECTED") : ImageID("I_RADIO_EMPTY"); },
new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(5, 0, 0, 0))));
new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(0.0f, 0.0f, 6.0f, 0.0f))));
LinearLayout *lines = Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(5, 5))));
LinearLayout *lines = Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(0.0f, 5))));
lines->SetSpacing(0.0f);
ClickableTextView *name = lines->Add(new ClickableTextView(entry.name));
name->SetFocusable(true);
@@ -547,6 +540,7 @@ AdhocServerRow::AdhocServerRow(std::string *editValue, const AdhocServerListEntr
e.v = this;
screenManager->push(new AdhocServerInfoScreen(copy));
});
infoButton->SetRoundCorners();
}
}
-1
View File
@@ -33,7 +33,6 @@ struct AdhocGame {
class AdhocServerCompactInfo : public UI::LinearLayout {
public:
AdhocServerCompactInfo(const AdhocServerListEntry &entry, UI::LayoutParams *layoutParams = nullptr);
void Draw(UIContext &dc) override;
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override {
w = 500; h = 100;
}
+1
View File
@@ -51,6 +51,7 @@ protected:
ViewLayoutMode LayoutMode() const override {
return ViewLayoutMode::ApplyInsets;
}
bool ReserveHiddenNavBar() const override { return true; }
void OnVKey(VirtKey virtualKeyCode, bool down) override;
private:
+18 -2
View File
@@ -173,6 +173,10 @@ static float g_safeInsetLeft = 0.0;
static float g_safeInsetRight = 0.0;
static float g_safeInsetTop = 0.0;
static float g_safeInsetBottom = 0.0;
static float g_navBarInsetLeft = 0.0;
static float g_navBarInsetRight = 0.0;
static float g_navBarInsetTop = 0.0;
static float g_navBarInsetBottom = 0.0;
static bool g_hasCameraCutout = false;
static bool g_hasAccelerometer = false;
static bool g_hasGyro = false;
@@ -400,6 +404,14 @@ float System_GetPropertyFloat(SystemProperty prop) {
return g_safeInsetTop * display_scale_y * g_display.dpi_scale_y;
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
return g_safeInsetBottom * display_scale_y * g_display.dpi_scale_y;
case SYSPROP_DISPLAY_NAVBAR_INSET_LEFT:
return g_navBarInsetLeft * display_scale_x * g_display.dpi_scale_x;
case SYSPROP_DISPLAY_NAVBAR_INSET_RIGHT:
return g_navBarInsetRight * display_scale_x * g_display.dpi_scale_x;
case SYSPROP_DISPLAY_NAVBAR_INSET_TOP:
return g_navBarInsetTop * display_scale_y * g_display.dpi_scale_y;
case SYSPROP_DISPLAY_NAVBAR_INSET_BOTTOM:
return g_navBarInsetBottom * display_scale_y * g_display.dpi_scale_y;
default:
return -1;
}
@@ -1466,13 +1478,17 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI
} else if (msg == "safe_insets") {
// INFO_LOG(Log::System, "Got insets: %s", prm.c_str());
// We don't bother with supporting exact rectangular regions. Safe insets are good enough.
int left, right, top, bottom, cutout;
if (5 == sscanf(prm.c_str(), "%d:%d:%d:%d:%d", &left, &right, &top, &bottom, &cutout)) {
int left, right, top, bottom, cutout, navLeft, navRight, navTop, navBottom;
if (9 == sscanf(prm.c_str(), "%d:%d:%d:%d:%d:%d:%d:%d:%d", &left, &right, &top, &bottom, &cutout, &navLeft, &navRight, &navTop, &navBottom)) {
g_safeInsetLeft = (float)left;
g_safeInsetRight = (float)right;
g_safeInsetTop = (float)top;
g_safeInsetBottom = (float)bottom;
g_hasCameraCutout = cutout != 0;
g_navBarInsetLeft = (float)navLeft;
g_navBarInsetRight = (float)navRight;
g_navBarInsetTop = (float)navTop;
g_navBarInsetBottom = (float)navBottom;
}
} else if (msg == "sensors") {
int accelerometer, gyro;
@@ -975,7 +975,10 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
int right = insets.right;
int top = insets.top;
int bottom = insets.bottom;
NativeApp.sendMessageFromJava("safe_insets", left + ":" + right + ":" + top + ":" + bottom + ":" + (hasCameraCutout ? 1 : 0));
// Where the navigation bar is when shown, which it is for a while after a swipe from the edge even when hidden.
Insets navBar = insetCompat.getInsetsIgnoringVisibility(WindowInsetsCompat.Type.navigationBars());
NativeApp.sendMessageFromJava("safe_insets", left + ":" + right + ":" + top + ":" + bottom + ":" + (hasCameraCutout ? 1 : 0)
+ ":" + navBar.left + ":" + navBar.right + ":" + navBar.top + ":" + navBar.bottom);
}
public void notifySurface(Surface surface) {