diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java index f9cdc4ccb..da6399ea6 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java @@ -117,17 +117,29 @@ public class AndroidPlatformSupport extends PlatformSupport { if (cutout != null) { boolean largeCutout = false; + boolean cutoutsPresent = false; + int screenSize = Game.width * Game.height; - for (Rect r : cutout.getBoundingRects()){ + for (Rect r : cutout.getBoundingRects()) { //use abs as some cutouts can apparently be returned inverted int cutoutSize = Math.abs(r.height() * r.width()); - //display cutouts are considered large if they take up more than 0.667% of the screen - //in reality we want less than about 0.5%, but some cutouts over-report their size - //Pixel devices especially =S - if (cutoutSize*150 >= screenSize){ - largeCutout = true; + //display cutouts are considered large if they take up more than 0.75% + // of the screen/ in reality we want less than about 0.5%, + // but some cutouts over-report their size, Pixel devices especially =S + if (cutoutSize > 0){ + cutoutsPresent = true; + if (cutoutSize * 133.33f >= screenSize) { + largeCutout = true; + } } } + + if (!cutoutsPresent){ + //if we get no cutouts reported, assume the device is lying to us + // and there actually is a cutout, which we must assume is large =S + largeCutout = true; + } + if (largeCutout || level == INSET_ALL) { insets.left = Math.max(insets.left, cutout.getSafeInsetLeft()); insets.top = Math.max(insets.top, cutout.getSafeInsetTop()); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 0267ff88c..9f8363718 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -369,10 +369,11 @@ public class GameScene extends PixelScene { int uiSize = SPDSettings.interfaceSize(); //display cutouts can obstruct various UI elements, so we need to adjust for that sometimes + float heroPaneExtraWidth = insets.left; float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; int hpBarMaxWidth = 50; //default max width float buffBarTopRowMaxWidth = 50; //default max width - if (largeInsetTop != insets.top){ + if (largeInsetTop == 0){ //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ //TODO bad to hardcode and approximate this atm @@ -380,10 +381,18 @@ public class GameScene extends PixelScene { float cutoutLeft = (Game.width*0.3f)/defaultZoom; buffBarTopRowMaxWidth = Math.min(50, cutoutLeft - 32); } else if (DeviceCompat.isAndroid()) { - //Android hole punches are of varying size and may obstruct the menu, HP bar, or buff bar + //Android hole punches are of varying size and may obstruct various UI elements RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); + //if the cutout is positioned to obstruct the hero portrait in the status pane + if (cutout.top < 30 + && cutout.left < 20 + && cutout.right > 12) { + heroPaneExtraWidth = Math.max(heroPaneExtraWidth, cutout.right-12); + //make sure we have space to actually move it though + heroPaneExtraWidth = Math.min(heroPaneExtraWidth, uiCamera.width - PixelScene.MIN_WIDTH_P); + } //if the cutout is positioned to obstruct the menu bar - if (cutout.top < 20 + else if (cutout.top < 20 && cutout.left < menuBarMaxLeft + MenuPane.WIDTH && cutout.right > menuBarMaxLeft) { menuBarMaxLeft = Math.min(menuBarMaxLeft, cutout.left - MenuPane.WIDTH); @@ -391,7 +400,7 @@ public class GameScene extends PixelScene { menuBarMaxLeft = Math.max(menuBarMaxLeft, PixelScene.MIN_WIDTH_P-MenuPane.WIDTH); } //if the cutout is positioned to obstruct the HP bar - if (cutout.left < 78 + else if (cutout.left < 78 && cutout.top < 4 && cutout.right > 32) { //subtract starting position, but add a bit back due to end of bar @@ -432,6 +441,7 @@ public class GameScene extends PixelScene { status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; + StatusPane.heroPaneExtraWidth = heroPaneExtraWidth; StatusPane.hpBarMaxWidth = hpBarMaxWidth; StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 0dea1410a..ac226cde8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -78,6 +78,9 @@ public class StatusPane extends Component { private boolean large; + //potentially extends the hero portrait space to avoid some cutouts + public static float heroPaneExtraWidth = 0; + private NinePatch heroPaneCutout; //potentially shrinks and/or repositions the hp bar to avoid some cutouts public static int hpBarMaxWidth = 50; private Image hpCutout; @@ -95,6 +98,10 @@ public class StatusPane extends Component { else bg = new NinePatch( asset, 0, 0, 82, 38, 32, 0, 5, 0 ); add( bg ); + heroPaneCutout = new NinePatch(asset, 0, 0, 5, 36, 4, 0, 0, 0); + heroPaneCutout.visible = false; + add(heroPaneCutout); + hpCutout = new Image(asset, 90, 0, 12, 9); hpCutout.visible = false; add(hpCutout); @@ -181,7 +188,9 @@ public class StatusPane extends Component { height = large ? 39 : 38; - bg.x = x; + float heroPaneWidth = 30 + heroPaneExtraWidth; + + bg.x = x + heroPaneExtraWidth; bg.y = y; if (large) bg.size( 160, bg.height ); //HP bars must be 128px wide atm else bg.size(hpBarMaxWidth+32, bg.height ); //default max right is 50px health bar + 32 @@ -190,7 +199,7 @@ public class StatusPane extends Component { avatar.y = bg.y - avatar.height / 2f + 16; PixelScene.align(avatar); - heroInfo.setRect( x, y, 30, large ? 40 : 36 ); + heroInfo.setRect( x, y, heroPaneWidth, large ? 40 : 36 ); compass.x = avatar.x + avatar.width / 2f - compass.origin.x; compass.y = avatar.y + avatar.height / 2f - compass.origin.y; @@ -221,7 +230,14 @@ public class StatusPane extends Component { exp.x = x+2; exp.y = y+30; - float hpleft = x + 30; + if (heroPaneExtraWidth > 0){ + heroPaneCutout.visible = true; + heroPaneCutout.x = x; + heroPaneCutout.y = y; + heroPaneCutout.size(heroPaneExtraWidth+4, heroPaneCutout.height); + } + + float hpleft = x + heroPaneWidth; if (hpBarMaxWidth < 82){ //the class variable assumes the left of the bar can't move, but we can inset it 9px int hpWidth = (int)hpBarMaxWidth; @@ -255,7 +271,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); buffs.firstRowWidth = buffBarTopRowMaxWidth; - buffs.setRect( x + 31, y + 8, 50, 15 ); + buffs.setRect( x + heroPaneWidth + 1, y + 8, 50, 15 ); busy.x = x + 1; busy.y = y + 37; @@ -322,7 +338,7 @@ public class StatusPane extends Component { expText.x = hp.x + (128 - expText.width())/2f; } else { - exp.scale.x = (17 / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); + exp.scale.x = ((17 + heroPaneExtraWidth) / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); expText.text(Dungeon.hero.exp + "/" + Dungeon.hero.maxExp()); } @@ -342,7 +358,7 @@ public class StatusPane extends Component { } else { level.text( Integer.toString( lastLvl ) ); level.measure(); - level.x = x + 25.5f - level.width() / 2f; + level.x = x + heroPaneExtraWidth + 25.5f - level.width() / 2f; level.y = y + 31.0f - level.baseLine() / 2f; } PixelScene.align(level); @@ -364,6 +380,8 @@ public class StatusPane extends Component { public void alpha( float value ){ value = GameMath.gate(0, value, 1f); bg.alpha(value); + heroPaneCutout.alpha(value); + hpCutout.alpha(value); avatar.alpha(value); rawShielding.alpha(0.5f*value); shieldedHP.alpha(value);