diff --git a/SPD-classes/src/main/java/com/watabou/utils/DeviceCompat.java b/SPD-classes/src/main/java/com/watabou/utils/DeviceCompat.java
index ecc8a0bb6..5e29a15e1 100644
--- a/SPD-classes/src/main/java/com/watabou/utils/DeviceCompat.java
+++ b/SPD-classes/src/main/java/com/watabou/utils/DeviceCompat.java
@@ -58,15 +58,6 @@ public class DeviceCompat {
Gdx.app.log( tag, message );
}
- public static RectF getSafeInsets(){
- RectF result = new RectF();
- result.left = Gdx.graphics.getSafeInsetLeft();
- result.top = Gdx.graphics.getSafeInsetTop();
- result.right = Gdx.graphics.getSafeInsetRight();
- result.bottom = Gdx.graphics.getSafeInsetBottom();
- return result;
- }
-
//some devices (macOS mainly) report virtual pixels to Shattered, but sometimes we want real pixel precision
//this returns the number of real pixels per virtual pixel in the X dimension...
public static float getRealPixelScaleX(){
diff --git a/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java b/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java
index d0921532e..2d016643f 100644
--- a/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java
+++ b/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java
@@ -39,6 +39,24 @@ public abstract class PlatformSupport {
public boolean supportsFullScreen(){
return true; //default
}
+
+ public static final int INSET_ALL = 3; //All insets, from hole punches to nav bars
+ public static final int INSET_LRG = 2; //Only big insets, full size notches and nav bars
+ public static final int INSET_BLK = 1; //only complete blocker assets like navbars
+
+ public RectF getSafeInsets( int level ){
+ return new RectF(
+ Gdx.graphics.getSafeInsetLeft(),
+ Gdx.graphics.getSafeInsetTop(),
+ Gdx.graphics.getSafeInsetRight(),
+ Gdx.graphics.getSafeInsetBottom()
+ );
+ }
+
+ //returns a display cutout (if one is present) in device pixels, or null is none is present
+ public RectF getDisplayCutout(){
+ return null;
+ }
public abstract void updateSystemUI();
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 7d98405f0..a23185fdc 100644
--- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java
+++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java
@@ -25,6 +25,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Build;
+import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -35,6 +36,7 @@ import com.badlogic.gdx.graphics.g2d.PixmapPacker;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.watabou.utils.PlatformSupport;
+import com.watabou.utils.RectF;
import java.util.HashMap;
import java.util.regex.Matcher;
@@ -45,6 +47,8 @@ public class AndroidPlatformSupport extends PlatformSupport {
public void updateDisplaySize(){
//TODO seem to be existing bugs with handling split screen here, should look into that
+
+ //TODO display isn't refreshing when fullscreen toggled on/off, or on 180 degree rotate
}
public boolean supportsFullScreen(){
@@ -56,7 +60,46 @@ public class AndroidPlatformSupport extends PlatformSupport {
return true;
}
}
-
+
+ @Override
+ public RectF getSafeInsets( int level ) {
+ RectF insets = new RectF();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ WindowInsets rootInsets = AndroidLauncher.instance.getApplicationWindow().getDecorView().getRootWindowInsets();
+ if (rootInsets != null) {
+
+ //Navigation bar (never on the top)
+ //Android 14 and below do this for us
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && supportsFullScreen() && !SPDSettings.fullscreen()) {
+ insets.left = Math.max(insets.left, rootInsets.getStableInsetLeft());
+ insets.right = Math.max(insets.right, rootInsets.getStableInsetRight());
+ insets.bottom = Math.max(insets.bottom, rootInsets.getStableInsetBottom());
+ }
+
+ //display cutout
+ if (level > INSET_BLK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ DisplayCutout cutout = rootInsets.getDisplayCutout();
+ //TODO determine if a cutout is large or not based on its size in pixels:
+ // on my OP7P, dev mode not simulations are:
+ //top-left cutout is 0,0,136,136 (136x136 = 18.5k total)
+ //center is 552,0,888,168 (336*168 = 56k total)
+ //top-right corner is 1272,0,1440,168 (x168 = 28k total)
+ //overall screen is 1440x3120 = 4400k pixels
+ // 0.5% of 4400k is 22k
+ //maybe judge a cutout to be large if it's bigger than 0.5% of the display?
+ if (cutout != null) {
+ insets.left = Math.max(insets.left, cutout.getSafeInsetLeft());
+ insets.top = Math.max(insets.top, cutout.getSafeInsetTop());
+ insets.right = Math.max(insets.right, cutout.getSafeInsetRight());
+ insets.bottom = Math.max(insets.bottom, cutout.getSafeInsetBottom());
+ }
+ }
+ }
+ }
+ return insets;
+ }
+
public void updateSystemUI() {
AndroidLauncher.instance.runOnUiThread(new Runnable() {
@@ -80,8 +123,9 @@ public class AndroidPlatformSupport extends PlatformSupport {
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY );
} else {
+ //still want to hide the status bar and cutout void
AndroidLauncher.instance.getWindow().getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN );
}
}
});
diff --git a/android/src/main/res/values/style.xml b/android/src/main/res/values/style.xml
index 59e8ec20e..195bf28c8 100644
--- a/android/src/main/res/values/style.xml
+++ b/android/src/main/res/values/style.xml
@@ -1,7 +1,9 @@
diff --git a/build.gradle b/build.gradle
index b9858b63b..b850c3244 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,9 +21,6 @@ allprojects {
appAndroidCompileSDK = 35 //Android 15
appAndroidMinSDK = 21 //Android 5.0
- // TODO currently we've opted-out of edge-to-edge but it will be required for Android 16
- // Need to figure out how the game will handle drawing into notches (and unify with iOS)
- // See: https://developer.android.com/about/versions/15/behavior-changes-15#ux
appAndroidTargetSDK = 35 //Android 15
gdxVersion = '1.13.6-SNAPSHOT' //using snapshot as 1.13.5 has issues with Android R8
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
index aad4414d1..42db5c1da 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
@@ -36,6 +36,7 @@ import com.watabou.noosa.Group;
import com.watabou.noosa.Image;
import com.watabou.noosa.PointerArea;
import com.watabou.noosa.ui.Component;
+import com.watabou.utils.RectF;
public class AboutScene extends PixelScene {
@@ -49,6 +50,8 @@ public class AboutScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
+
Archs archs = new Archs();
archs.setSize( w, h );
add( archs );
@@ -71,9 +74,9 @@ public class AboutScene extends PixelScene {
"ShatteredPixel.com",
"https://ShatteredPixel.com");
if (landscape()){
- shpx.setRect((w - fullWidth)/2f - 6, 10, 120, 0);
+ shpx.setRect((w - fullWidth)/2f - 6, insets.top + 10, 120, 0);
} else {
- shpx.setRect((w - fullWidth)/2f, 6, 120, 0);
+ shpx.setRect((w - fullWidth)/2f, insets.top + 6, 120, 0);
}
content.add(shpx);
@@ -232,7 +235,7 @@ public class AboutScene extends PixelScene {
freesound.setRect(transifex.left()-10, transifex.bottom() + 8, colWidth+20, 0);
content.add(freesound);
- content.setSize( fullWidth, freesound.bottom()+10 );
+ content.setSize( fullWidth, freesound.bottom()+10 + insets.bottom );
list.setRect( 0, 0, w, h );
list.scrollTo(0, 0);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AlchemyScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AlchemyScene.java
index b109b0006..92384366d 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AlchemyScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AlchemyScene.java
@@ -79,6 +79,7 @@ import com.watabou.noosa.SkinnedBlock;
import com.watabou.noosa.audio.Sample;
import com.watabou.noosa.particles.Emitter;
import com.watabou.noosa.ui.Component;
+import com.watabou.utils.RectF;
import java.io.IOException;
import java.util.ArrayList;
@@ -120,9 +121,13 @@ public class AlchemyScene extends PixelScene {
@Override
public void create() {
super.create();
-
+
+ int w = Camera.main.width;
+ int h = Camera.main.height;
+ RectF insets = getCommonInsets();
+
water = new SkinnedBlock(
- Camera.main.width, Camera.main.height,
+ w, h,
Dungeon.level.waterTex() ){
@Override
@@ -143,18 +148,21 @@ public class AlchemyScene extends PixelScene {
Image im = new Image(TextureCache.createGradient(0x66000000, 0x88000000, 0xAA000000, 0xCC000000, 0xFF000000));
im.angle = 90;
- im.x = Camera.main.width;
- im.scale.x = Camera.main.height/5f;
- im.scale.y = Camera.main.width;
+ im.x = w;
+ im.scale.x = h/5f;
+ im.scale.y = w;
add(im);
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
ExitButton btnExit = new ExitButton(){
@Override
protected void onClick() {
Game.switchScene(GameScene.class);
}
};
- btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
+ btnExit.setPos( insets.left + w - btnExit.width(), insets.top );
add( btnExit );
bubbleEmitter = new Emitter();
@@ -166,30 +174,30 @@ public class AlchemyScene extends PixelScene {
IconTitle title = new IconTitle(Icons.ALCHEMY.get(), Messages.get(this, "title") );
title.setSize(200, 0);
title.setPos(
- (Camera.main.width - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
- int w = Math.min(50 + Camera.main.width/2, 150);
- int left = (Camera.main.width - w)/2;
+ int pw = Math.min(50 + w/2, 150);
+ int left = (int)(insets.left) + (w - pw)/2;
- centerW = left + w/2;
+ centerW = left + pw/2;
- int pos = (Camera.main.height - 120)/2;
+ int pos = (int)(insets.top) + (h - 120)/2;
if (splitAlchGuide &&
- Camera.main.width >= 300 &&
- Camera.main.height >= PixelScene.MIN_HEIGHT_FULL){
- w = Math.min(150, Camera.main.width/2);
- left = (Camera.main.width/2 - w);
- centerW = left + w/2;
+ w >= 300 &&
+ h >= PixelScene.MIN_HEIGHT_FULL){
+ pw = Math.min(150, w/2);
+ left = (w/2 - pw);
+ centerW = left + pw/2;
NinePatch guideBG = Chrome.get(Chrome.Type.TOAST);
guideBG.size(126 + guideBG.marginHor(), Math.min(Camera.main.height - 18, 191 + guideBG.marginVer()));
- guideBG.y = Math.max(17, (Camera.main.height - guideBG.height())/2f);
- guideBG.x = Camera.main.width - left - guideBG.width();
+ guideBG.y = Math.max(17, insets.top + (h - guideBG.height())/2f);
+ guideBG.x = insets.left + w - left - guideBG.width();
add(guideBG);
alchGuide = new WndJournal.AlchemyTab();
@@ -204,9 +212,9 @@ public class AlchemyScene extends PixelScene {
}
RenderedTextBlock desc = PixelScene.renderTextBlock(6);
- desc.maxWidth(w);
+ desc.maxWidth(pw);
desc.text( Messages.get(AlchemyScene.class, "text") );
- desc.setPos(left + (w - desc.width())/2, pos);
+ desc.setPos(left + (pw - desc.width())/2, pos);
add(desc);
pos += desc.height() + 6;
@@ -383,8 +391,8 @@ public class AlchemyScene extends PixelScene {
if (i == 0){
//first ones are always visible
- combines[i].setRect(left + (w-30)/2f, inputs[1].top()+5, 30, inputs[1].height()-10);
- outputs[i].setRect(left + w - BTN_SIZE - 10, inputs[1].top(), BTN_SIZE, BTN_SIZE);
+ combines[i].setRect(left + (pw-30)/2f, inputs[1].top()+5, 30, inputs[1].height()-10);
+ outputs[i].setRect(left + pw - BTN_SIZE - 10, inputs[1].top(), BTN_SIZE, BTN_SIZE);
} else {
combines[i].visible = false;
outputs[i].visible = false;
@@ -403,7 +411,7 @@ public class AlchemyScene extends PixelScene {
if (Camera.main.height >= 280){
//last elements get centered even with a split alch guide UI, as long as there's enough height
- centerW = Camera.main.width/2;
+ centerW = (int)(insets.left) + w/2;
}
bubbleEmitter.pos(0,
@@ -415,7 +423,7 @@ public class AlchemyScene extends PixelScene {
lowerBubbles.pos(0,
pos,
2*centerW,
- Math.max(0, Camera.main.height-pos));
+ Math.max(0, h-pos));
lowerBubbles.pour(Speck.factory( Speck.BUBBLE ), 0.1f );
String energyText = Messages.get(AlchemyScene.class, "energy") + " " + Dungeon.energy;
@@ -426,7 +434,7 @@ public class AlchemyScene extends PixelScene {
energyLeft = PixelScene.renderTextBlock(energyText, 9);
energyLeft.setPos(
centerW - energyLeft.width()/2,
- Camera.main.height - 8 - energyLeft.height()
+ insets.top + h - 8 - energyLeft.height()
);
energyLeft.hardlight(0x44CCFF);
add(energyLeft);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AmuletScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AmuletScene.java
index 6917751c1..12b304fa3 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AmuletScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AmuletScene.java
@@ -42,6 +42,7 @@ import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Music;
import com.watabou.noosa.tweeners.Delayer;
import com.watabou.utils.Random;
+import com.watabou.utils.RectF;
public class AmuletScene extends PixelScene {
@@ -119,30 +120,34 @@ public class AmuletScene extends PixelScene {
btnStay.icon(Icons.CLOSE.get());
btnStay.setSize( WIDTH, BTN_HEIGHT );
add( btnStay );
-
+
+ RectF insets = getCommonInsets();
+ int w = (int) (Camera.main.width - insets.left + insets.right);
+ int h = (int) (Camera.main.height - insets.top + insets.bottom);
+
float height;
if (noText) {
height = amulet.height + LARGE_GAP + btnExit.height() + SMALL_GAP + btnStay.height();
- amulet.x = (Camera.main.width - amulet.width) / 2;
- amulet.y = (Camera.main.height - height) / 2;
+ amulet.x = insets.left + (w - amulet.width) / 2;
+ amulet.y = insets.top + (h - height) / 2;
align(amulet);
- btnExit.setPos( (Camera.main.width - btnExit.width()) / 2, amulet.y + amulet.height + LARGE_GAP );
+ btnExit.setPos( insets.left + (w - btnExit.width()) / 2, amulet.y + amulet.height + LARGE_GAP );
btnStay.setPos( btnExit.left(), btnExit.bottom() + SMALL_GAP );
} else {
height = amulet.height + LARGE_GAP + text.height() + LARGE_GAP + btnExit.height() + SMALL_GAP + btnStay.height();
-
- amulet.x = (Camera.main.width - amulet.width) / 2;
- amulet.y = (Camera.main.height - height) / 2;
+
+ amulet.x = insets.left + (w - amulet.width) / 2;
+ amulet.y = insets.top + (h - height) / 2;
align(amulet);
- text.setPos((Camera.main.width - text.width()) / 2, amulet.y + amulet.height + LARGE_GAP);
+ text.setPos(insets.left + (w - text.width()) / 2, amulet.y + amulet.height + LARGE_GAP);
align(text);
add(text);
-
- btnExit.setPos( (Camera.main.width - btnExit.width()) / 2, text.top() + text.height() + LARGE_GAP );
+
+ btnExit.setPos( insets.left + (w - btnExit.width()) / 2, amulet.y + amulet.height + LARGE_GAP );
btnStay.setPos( btnExit.left(), btnExit.bottom() + SMALL_GAP );
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
index d40a27b8d..ab762c1b2 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
@@ -55,6 +55,7 @@ import com.watabou.noosa.NinePatch;
import com.watabou.noosa.Scene;
import com.watabou.noosa.audio.Music;
import com.watabou.noosa.ui.Component;
+import com.watabou.utils.RectF;
import java.util.ArrayList;
@@ -79,17 +80,26 @@ public class ChangesScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
+
+ Archs archs = new Archs();
+ archs.setSize(w, h);
+ //archs added later
+
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
IconTitle title = new IconTitle(Icons.CHANGES.get(), Messages.get(this, "title"));
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
ExitButton btnExit = new ExitButton();
- btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
+ btnExit.setPos( insets.left + w - btnExit.width(), insets.top );
add( btnExit );
NinePatch panel = Chrome.get(Chrome.Type.TOAST);
@@ -99,8 +109,8 @@ public class ChangesScene extends PixelScene {
if (h >= PixelScene.MIN_HEIGHT_FULL && w >= 300) {
panel.size( pw, ph );
- panel.x = (w - pw) / 2f - pw/2 - 1;
- panel.y = 20;
+ panel.x = insets.left + (w - pw) / 2f - pw/2 - 1;
+ panel.y = insets.top + 20;
rightPanel = Chrome.get(Chrome.Type.TOAST);
rightPanel.size( pw, ph );
@@ -131,8 +141,8 @@ public class ChangesScene extends PixelScene {
} else {
panel.size( pw, ph );
- panel.x = (w - pw) / 2f;
- panel.y = 20;
+ panel.x = insets.left + (w - pw) / 2f;
+ panel.y = insets.top + 20;
}
align( panel );
add( panel );
@@ -340,8 +350,6 @@ public class ChangesScene extends PixelScene {
btnOld.setRect(btn0_6.right()-2, btn0_8.top(), 22, changesSelected == 7 ? 19 : 15);
addToBack(btnOld);
- Archs archs = new Archs();
- archs.setSize( Camera.main.width, Camera.main.height );
addToBack( archs );
fadeIn();
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 288fb49b4..9730167ea 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java
@@ -121,6 +121,7 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndKeyBindings;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndMessage;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndResurrect;
+import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Blending;
import com.watabou.input.ControllerHandler;
import com.watabou.input.KeyBindings;
@@ -138,8 +139,8 @@ import com.watabou.noosa.audio.Sample;
import com.watabou.noosa.particles.Emitter;
import com.watabou.noosa.tweeners.Tweener;
import com.watabou.utils.Callback;
-import com.watabou.utils.DeviceCompat;
import com.watabou.utils.GameMath;
+import com.watabou.utils.PlatformSupport;
import com.watabou.utils.Point;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
@@ -231,6 +232,8 @@ public class GameScene extends PixelScene {
case 1: Camera.main.setFollowDeadzone(0.9f); break;
}
+ RectF insets = Game.platform.getSafeInsets(PlatformSupport.INSET_ALL).scale(1f/defaultZoom);
+
scene = this;
terrain = new Group();
@@ -361,16 +364,24 @@ public class GameScene extends PixelScene {
int uiSize = SPDSettings.interfaceSize();
+ //TODO this is a good start but just emulating black bars is boring. There must be more to do here.
+
menu = new MenuPane();
menu.camera = uiCamera;
- menu.setPos( uiCamera.width-MenuPane.WIDTH, uiSize > 0 ? 0 : 1);
+ menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, insets.top + (uiSize > 0 ? 0 : 1));
add(menu);
status = new StatusPane( SPDSettings.interfaceSize() > 0 );
status.camera = uiCamera;
- status.setRect(0, uiSize > 0 ? uiCamera.height-39 : 0, uiCamera.width, 0 );
+ status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : insets.top, uiCamera.width - insets.left - insets.right, 0 );
add(status);
+ if (uiSize < 2 && insets.top > 0) {
+ SkinnedBlock blackBar = new SkinnedBlock(uiCamera.width, insets.top, TextureCache.createSolid(0xFF000000));
+ blackBar.camera = uiCamera;
+ add(blackBar);
+ }
+
boss = new BossHealthBar();
boss.camera = uiCamera;
boss.setPos( 6 + (uiCamera.width - boss.width())/2, 20);
@@ -411,9 +422,9 @@ public class GameScene extends PixelScene {
inventory.setPos(uiCamera.width - inventory.width(), uiCamera.height - inventory.height());
add(inventory);
- toolbar.setRect( 0, uiCamera.height - toolbar.height() - inventory.height(), uiCamera.width, toolbar.height() );
+ toolbar.setRect( insets.left, uiCamera.height - toolbar.height() - inventory.height() - insets.bottom, uiCamera.width - insets.right, toolbar.height() );
} else {
- toolbar.setRect( 0, uiCamera.height - toolbar.height(), uiCamera.width, toolbar.height() );
+ toolbar.setRect( insets.left, uiCamera.height - toolbar.height() - insets.bottom, uiCamera.width - insets.right, toolbar.height() );
}
layoutTags();
@@ -840,7 +851,7 @@ public class GameScene extends PixelScene {
//primarily for phones displays with notches
//TODO Android never draws into notch atm, perhaps allow it for center notches?
- RectF insets = DeviceCompat.getSafeInsets();
+ RectF insets = Game.platform.getSafeInsets( PlatformSupport.INSET_ALL );
insets = insets.scale(1f / uiCamera.zoom);
boolean tagsOnLeft = SPDSettings.flipTags();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java
index 462bf32e5..1181a003a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java
@@ -59,7 +59,9 @@ import com.watabou.noosa.tweeners.Tweener;
import com.watabou.noosa.ui.Component;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.GameMath;
+import com.watabou.utils.PlatformSupport;
import com.watabou.utils.PointF;
+import com.watabou.utils.RectF;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -84,6 +86,8 @@ public class HeroSelectScene extends PixelScene {
private GameOptions optionsPane;
private IconButton btnExit;
+ private RectF insets;
+
@Override
public void create() {
super.create();
@@ -93,6 +97,11 @@ public class HeroSelectScene extends PixelScene {
Badges.loadGlobal();
Journal.loadGlobal();
+ insets = Game.platform.getSafeInsets(PlatformSupport.INSET_BLK).scale(1f/defaultZoom);
+
+ int w = (int)(Camera.main.width - insets.left - insets.right);
+ int h = (int)(Camera.main.height - insets.top - insets.bottom);
+
background = new Image(TextureCache.createSolid(0xFF2d2f31), 0, 0, 800, 450){
@Override
public void update() {
@@ -106,10 +115,10 @@ public class HeroSelectScene extends PixelScene {
}
}
};
- background.scale.set(Camera.main.height/background.height);
+ background.scale.set(h/background.height);
- background.x = (Camera.main.width - background.width())/2f;
- background.y = (Camera.main.height - background.height())/2f;
+ background.x = insets.left + (w - background.width())/2f;
+ background.y = insets.top + (h - background.height())/2f;
PixelScene.align(background);
add(background);
@@ -157,11 +166,11 @@ public class HeroSelectScene extends PixelScene {
super.onClick();
HeroClass cls = GamesInProgress.selectedClass;
if (cls != null) {
- Window w = new WndHeroInfo(GamesInProgress.selectedClass);
+ Window info = new WndHeroInfo(GamesInProgress.selectedClass);
if (landscape()) {
- w.offset(Camera.main.width / 6, 0);
+ info.offset(w / 6, 0);
}
- ShatteredPixelDungeon.scene().addToFront(w);
+ ShatteredPixelDungeon.scene().addToFront(info);
}
}
@@ -222,19 +231,19 @@ public class HeroSelectScene extends PixelScene {
}
if (landscape()){
- float leftArea = Math.max(100, Camera.main.width/3f);
- float uiHeight = Math.min(Camera.main.height-20, 300);
+ float leftArea = Math.max(100, w/3f);
+ float uiHeight = Math.min(h-20, 300);
float uiSpacing = (uiHeight-120)/2f;
if (uiHeight >= 160) uiSpacing -= 5;
if (uiHeight >= 180) uiSpacing -= 6;
- background.x += leftArea/6f;
+ background.x += insets.left + leftArea/6f;
float fadeLeftScale = 47 * (leftArea - background.x)/leftArea;
fadeLeft.scale = new PointF(3 + Math.max(0, fadeLeftScale), background.height());
- title.setPos( (leftArea - title.width())/2f, (Camera.main.height-uiHeight)/2f);
+ title.setPos(insets.left + (leftArea - title.width())/2f, (h-uiHeight)/2f);
align(title);
int btnWidth = HeroBtn.MIN_WIDTH + 15;
@@ -244,7 +253,7 @@ public class HeroSelectScene extends PixelScene {
}
int cols = (int)Math.ceil(heroBtns.size()/2f);
- float curX = (leftArea - btnWidth * cols + (cols-1))/2f;
+ float curX = insets.left + (leftArea - btnWidth * cols + (cols-1))/2f;
float curY = title.bottom() + uiSpacing;
int count = 0;
@@ -264,7 +273,7 @@ public class HeroSelectScene extends PixelScene {
}
heroName = renderTextBlock(9);
- heroName.setPos(0, heroBtns.get(heroBtns.size()-1).bottom()+5);
+ heroName.setPos(insets.left, heroBtns.get(heroBtns.size()-1).bottom()+5);
add(heroName);
if (uiHeight >= 160){
@@ -273,12 +282,12 @@ public class HeroSelectScene extends PixelScene {
heroDesc = renderTextBlock(5);
}
heroDesc.align(RenderedTextBlock.CENTER_ALIGN);
- heroDesc.setPos(0, heroName.bottom()+5);
+ heroDesc.setPos(insets.left, heroName.bottom()+5);
add(heroDesc);
startBtn.text(Messages.titleCase(Messages.get(this, "start")));
startBtn.setSize(startBtn.reqWidth()+8, 21);
- startBtn.setPos((leftArea - startBtn.width())/2f, title.top() + uiHeight - startBtn.height());
+ startBtn.setPos(insets.left + (leftArea - startBtn.width())/2f, title.top() + uiHeight - startBtn.height());
align(startBtn);
btnFade = new IconButton(Icons.CHEVRON.get()){
@@ -309,19 +318,19 @@ public class HeroSelectScene extends PixelScene {
int btnWidth = HeroBtn.MIN_WIDTH;
- float curX = (Camera.main.width - btnWidth * heroBtns.size()) / 2f;
+ float curX = insets.left + (w - btnWidth * heroBtns.size()) / 2f;
if (curX > 0) {
btnWidth += Math.min(curX / (heroBtns.size() / 2f), 15);
- curX = (Camera.main.width - btnWidth * heroBtns.size()) / 2f;
+ curX = insets.left + (w - btnWidth * heroBtns.size()) / 2f;
}
- float curY = Camera.main.height - HeroBtn.HEIGHT + 3;
+ float curY = insets.top + h - HeroBtn.HEIGHT + 3;
for (StyledButton button : heroBtns) {
button.setRect(curX, curY, btnWidth, HeroBtn.HEIGHT);
curX += btnWidth;
}
- title.setPos((Camera.main.width - title.width()) / 2f, (Camera.main.height - HeroBtn.HEIGHT - title.height() - 4));
+ title.setPos(insets.left + (w - title.width()) / 2f, insets.top + (h - HeroBtn.HEIGHT - title.height() - 4));
btnOptions.setRect(heroBtns.get(0).left() + 16, Camera.main.height-HeroBtn.HEIGHT-16, 20, 21);
optionsPane.setPos(heroBtns.get(0).left(), 0);
@@ -396,23 +405,23 @@ public class HeroSelectScene extends PixelScene {
background.visible = true;
background.hardlight(1.5f,1.5f,1.5f);
- float leftPortion = Math.max(100, Camera.main.width/3f);
+ float leftPortion = Math.max(100, (Camera.main.width - insets.left - insets.right)/3f);
if (landscape()) {
heroName.text(Messages.titleCase(cl.title()));
heroName.hardlight(Window.TITLE_COLOR);
- heroName.setPos((leftPortion - heroName.width() - 20)/2f, heroName.top());
+ heroName.setPos(insets.left + (leftPortion - heroName.width() - 20)/2f, heroName.top());
align(heroName);
heroDesc.text(cl.shortDesc());
heroDesc.maxWidth(80);
- heroDesc.setPos((leftPortion - heroDesc.width())/2f, heroName.bottom() + 5);
+ heroDesc.setPos(insets.left +(leftPortion - heroDesc.width())/2f, heroName.bottom() + 5);
align(heroDesc);
while(startBtn.top() < heroDesc.bottom()){
heroDesc.maxWidth(heroDesc.maxWidth()+10);
- heroDesc.setPos(Math.max(0, (leftPortion - heroDesc.width())/2f), heroName.bottom() + 5);
+ heroDesc.setPos(Math.max(insets.left, (leftPortion - heroDesc.width())/2f), heroName.bottom() + 5);
align(heroDesc);
}
@@ -433,7 +442,7 @@ public class HeroSelectScene extends PixelScene {
startBtn.text(Messages.titleCase(cl.title()));
startBtn.setSize(startBtn.reqWidth() + 8, 21);
- startBtn.setPos((Camera.main.width - startBtn.width())/2f, (Camera.main.height - HeroBtn.HEIGHT + 2 - startBtn.height()));
+ startBtn.setPos((Camera.main.width - startBtn.width())/2f, (Camera.main.height - insets.bottom - HeroBtn.HEIGHT + 2 - startBtn.height()));
PixelScene.align(startBtn);
infoButton.visible = infoButton.active = true;
@@ -496,13 +505,15 @@ public class HeroSelectScene extends PixelScene {
if (landscape()){
- background.x = (Camera.main.width - background.width())/2f;
+ int w = (int)(Camera.main.width - insets.left - insets.right);
- float leftPortion = Math.max(100, Camera.main.width/3f);
+ background.x = insets.left + (w - background.width())/2f;
+
+ float leftPortion = Math.max(100, w/3f);
background.x += (leftPortion/2f)*alpha;
- float fadeLeftScale = 47 * (leftPortion - background.x)/leftPortion;
+ float fadeLeftScale = 47 * (leftPortion - (background.x - insets.left))/leftPortion;
fadeLeft.scale.x = 3 + Math.max(fadeLeftScale, 0)*alpha;
fadeLeft.x = background.x-4;
fadeRight.x = background.x + background.width() + 4;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
index 5c993e7ac..ddc595a41 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
@@ -56,7 +56,9 @@ import com.watabou.noosa.tweeners.Tweener;
import com.watabou.utils.BArray;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.GameMath;
+import com.watabou.utils.PlatformSupport;
import com.watabou.utils.Random;
+import com.watabou.utils.RectF;
import com.watabou.utils.Signal;
import java.io.FileNotFoundException;
@@ -107,6 +109,8 @@ public class InterlevelScene extends PixelScene {
public static int lastRegion = -1;
+ private RectF insets;
+
{
inGameScene = true;
}
@@ -210,16 +214,21 @@ public class InterlevelScene extends PixelScene {
fadeTime = 0f;
}
- background = new Image(loadingAsset);
- background.scale.set(Camera.main.height/background.height);
+ insets = Game.platform.getSafeInsets(PlatformSupport.INSET_BLK).scale(1f/defaultZoom);
- if (Camera.main.width >= background.width()){
- background.x = (Camera.main.width - background.width())/2f;
+ int w = (int)(Camera.main.width - insets.left - insets.right);
+ int h = (int)(Camera.main.height - insets.top - insets.bottom);
+
+ background = new Image(loadingAsset);
+ background.scale.set(h/background.height);
+
+ if (w >= background.width()){
+ background.x = insets.left + (w - background.width())/2f;
} else {
- background.x = Camera.main.width/2f - loadingCenter*background.scale.x;
- background.x = GameMath.gate(Camera.main.width - background.width(), background.x, 0);
+ background.x = insets.left + w/2f - loadingCenter*background.scale.x;
+ background.x = GameMath.gate(w - background.width(), background.x, 0);
}
- background.y = (Camera.main.height - background.height())/2f;
+ background.y = insets.top + (h - background.height())/2f;
PixelScene.align(background);
add(background);
@@ -248,17 +257,17 @@ public class InterlevelScene extends PixelScene {
}
};
im.angle = 90;
- im.x = Camera.main.width;
- im.scale.x = Camera.main.height/5f;
- im.scale.y = Camera.main.width;
+ im.x = insets.left + w;
+ im.scale.x = h/5f;
+ im.scale.y = w;
add(im);
String text = Messages.get(Mode.class, mode.name());
loadingText = PixelScene.renderTextBlock( text, 9 );
loadingText.setPos(
- (Camera.main.width - loadingText.width() - 8),
- (Camera.main.height - loadingText.height() - 6)
+ insets.left + w - loadingText.width() - 8,
+ insets.top + h - loadingText.height() - 6
);
align(loadingText);
add(loadingText);
@@ -267,7 +276,7 @@ public class InterlevelScene extends PixelScene {
if (Dungeon.hero == null || (loadingDepth > Statistics.deepestFloor && loadingDepth % 5 == 1)){
storyMessage = PixelScene.renderTextBlock(Document.INTROS.pageBody(region), 6);
storyMessage.maxWidth( PixelScene.landscape() ? 180 : 125);
- storyMessage.setPos((Camera.main.width-storyMessage.width())/2f, (Camera.main.height-storyMessage.height())/2f);
+ storyMessage.setPos(insets.left+(w-storyMessage.width())/2f, insets.top+(h-storyMessage.height())/2f);
storyBG = new ShadowBox();
storyBG.boxRect(storyMessage.left()-10, storyMessage.top()-10, storyMessage.width()+20, storyMessage.height()+20);
@@ -322,7 +331,7 @@ public class InterlevelScene extends PixelScene {
}
});
- btnContinue.setPos((Camera.main.width - btnContinue.width())/2f, storyMessage.bottom()+10);
+ btnContinue.setPos(insets.left + (w - btnContinue.width())/2f, storyMessage.bottom()+10);
add(btnContinue);
btnHideStory = new IconButton(Icons.CHEVRON.get()){
@@ -474,6 +483,9 @@ public class InterlevelScene extends PixelScene {
break;
}
}
+
+ int w = (int)(Camera.main.width - insets.left - insets.right);
+ int h = (int)(Camera.main.height - insets.top - insets.bottom);
switch (phase) {
@@ -528,12 +540,13 @@ public class InterlevelScene extends PixelScene {
//slowly pan the background side to side in portait mode, if story text is displayed
if (btnContinue != null && !textFadingIn && Game.width < Game.height){
if (background.speed.isZero() && background.acc.isZero()){
- background.acc.x = background.center().x >= Camera.main.width ? -1f : 1f;
+ background.acc.x = background.center().x >= (w+ insets.left) ? -1f : 1f;
} else {
+ float margin = 25 - insets.left;
background.speed.x = GameMath.gate(-10, background.speed.x, 10);
- if (background.acc.x > 0 && background.x >= -25){
+ if (background.acc.x > 0 && background.x >= -margin){
background.acc.x = -2.5f;
- } else if (background.acc.x < 0 && background.x + background.width() <= Camera.main.width+25){
+ } else if (background.acc.x < 0 && background.x + background.width() <= w+margin){
background.acc.x = 2.5f;
}
}
@@ -581,8 +594,8 @@ public class InterlevelScene extends PixelScene {
//the randomization is effectively -2 to +2
// we don't use the generator stack as levelgen may be occurring
// and we don't want to accidentally use a seeded generator
- (Camera.main.width - loadingText.width() - 4) + 4*(Random.Float(false)-0.5f),
- (Camera.main.height - loadingText.height() - 6) + 4*(Random.Float(false)-0.5f)
+ (w + insets.left - loadingText.width() - 4) + 4*(Random.Float(false)-0.5f),
+ (h + insets.top - loadingText.height() - 6) + 4*(Random.Float(false)-0.5f)
);
align(loadingText);
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
index 53fb82f76..361374e07 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
@@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal;
import com.watabou.noosa.Camera;
import com.watabou.noosa.NinePatch;
import com.watabou.noosa.audio.Music;
+import com.watabou.utils.RectF;
import com.watabou.utils.SparseArray;
public class JournalScene extends PixelScene {
@@ -79,13 +80,22 @@ public class JournalScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
+
+ Archs archs = new Archs();
+ archs.setSize( w, h );
+ //archs added later
+
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
float top = 20;
IconTitle title = new IconTitle( Icons.JOURNAL.get(), Messages.get(this, "title") );
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (top - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (top - title.height()) / 2f
);
align(title);
add(title);
@@ -96,8 +106,8 @@ public class JournalScene extends PixelScene {
int ph = h - 50 + panel.marginVer();
panel.size(pw, ph);
- panel.x = (w - pw) / 2f;
- panel.y = top;
+ panel.x = insets.left + (w - pw) / 2f;
+ panel.y = insets.top + top;
add(panel);
switch (lastIDX){
@@ -218,12 +228,10 @@ public class JournalScene extends PixelScene {
if (lastIDX != 3) btnAlchemy.icon().brightness(0.6f);
addToBack(btnAlchemy);
- Archs archs = new Archs();
- archs.setSize( w, h );
- addToBack( archs );
+ addToBack(archs);
ExitButton btnExit = new ExitButton();
- btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
+ btnExit.setPos( insets.left + w - btnExit.width(), insets.top );
add( btnExit );
fadeIn();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
index 5de715152..5fabd82a0 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
@@ -43,6 +43,7 @@ import com.watabou.noosa.Camera;
import com.watabou.noosa.Game;
import com.watabou.noosa.NinePatch;
import com.watabou.noosa.ui.Component;
+import com.watabou.utils.RectF;
import java.util.ArrayList;
@@ -61,34 +62,38 @@ public class NewsScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
-
- int fullWidth = PixelScene.landscape() ? 202 : 100;
- int left = (w - fullWidth)/2;
+ RectF insets = getCommonInsets();
Archs archs = new Archs();
archs.setSize(w, h);
add(archs);
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
+ int fullWidth = PixelScene.landscape() ? 202 : 100;
+ int left = (int)insets.left + (w - fullWidth)/2;
+
ExitButton btnExit = new ExitButton();
- btnExit.setPos(w - btnExit.width(), 0);
+ btnExit.setPos(insets.left + w - btnExit.width(), insets.top);
add(btnExit);
IconTitle title = new IconTitle( Icons.NEWS.get(), Messages.get(this, "title"));
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
- float top = 18;
+ float top = 18 + insets.top;
displayingNoArticles = !News.articlesAvailable();
if (displayingNoArticles || Messages.lang() != Languages.ENGLISH) {
Component newsInfo = new NewsInfo();
- newsInfo.setRect(left, 20, fullWidth, 0);
+ newsInfo.setRect(left, top, fullWidth, 0);
add(newsInfo);
top = newsInfo.bottom();
@@ -98,7 +103,7 @@ public class NewsScene extends PixelScene {
if (!displayingNoArticles) {
ArrayList articles = News.articles();
- float articleSpace = h - top - 2;
+ float articleSpace = h - top - 2 + insets.top;
int rows = articles.size();
if (PixelScene.landscape()){
rows /= 2;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
index 46b6cfdb3..f29552080 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
@@ -52,7 +52,9 @@ import com.watabou.noosa.ui.Cursor;
import com.watabou.utils.Callback;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.GameMath;
+import com.watabou.utils.PlatformSupport;
import com.watabou.utils.PointF;
+import com.watabou.utils.RectF;
import com.watabou.utils.Reflection;
import com.watabou.utils.Signal;
@@ -119,7 +121,13 @@ public class PixelScene extends Scene {
scaleFactor = 2.5f;
}
- maxDefaultZoom = (int)Math.min(Game.width/minWidth, Game.height/minHeight);
+ //TODO all insets? or just blockers?
+ RectF insets = Game.platform.getSafeInsets(PlatformSupport.INSET_ALL);
+
+ float w = Game.width - insets.left - insets.right;
+ float h = Game.height - insets.top - insets.bottom;
+
+ maxDefaultZoom = (int)Math.min(w/minWidth, h/minHeight);
maxDefaultZoom = Math.max(2, maxDefaultZoom);
defaultZoom = SPDSettings.scale();
@@ -397,6 +405,18 @@ public class PixelScene extends Scene {
magnitude *= SPDSettings.screenShake();
Camera.main.shake(magnitude, duration);
}
+
+ //returns insets for the common case of all on top/bottom and only blocking on left/right
+ //plus scaled to pixel zoom
+ public RectF getCommonInsets(){
+ RectF all = Game.platform.getSafeInsets(PlatformSupport.INSET_ALL);
+ RectF blocking = Game.platform.getSafeInsets(PlatformSupport.INSET_BLK);
+
+ all.left = blocking.left;
+ all.right = blocking.right;
+
+ return all.scale(1f/defaultZoom);
+ }
protected static class Fader extends ColorBlock {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
index 553834840..19363ae0c 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
@@ -48,6 +48,7 @@ import com.watabou.noosa.Camera;
import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Music;
import com.watabou.utils.GameMath;
+import com.watabou.utils.RectF;
public class RankingsScene extends PixelScene {
@@ -74,18 +75,22 @@ public class RankingsScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
-
+ RectF insets = getCommonInsets();
+
archs = new Archs();
archs.setSize( w, h );
add( archs );
-
+
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
Rankings.INSTANCE.load();
IconTitle title = new IconTitle( Icons.RANKINGS.get(), Messages.get(this, "title"));
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
@@ -93,7 +98,7 @@ public class RankingsScene extends PixelScene {
if (Rankings.INSTANCE.records.size() > 0) {
//attempts to give each record as much space as possible, ideally as much space as portrait mode
- float rowHeight = GameMath.gate(ROW_HEIGHT_MIN, (uiCamera.height - 26)/Rankings.INSTANCE.records.size(), ROW_HEIGHT_MAX);
+ float rowHeight = GameMath.gate(ROW_HEIGHT_MIN, (h - 26)/Rankings.INSTANCE.records.size(), ROW_HEIGHT_MAX);
float left = (w - Math.min( MAX_ROW_WIDTH, w )) / 2 + GAP;
float top = (h - rowHeight * Rankings.INSTANCE.records.size()) / 2;
@@ -106,7 +111,7 @@ public class RankingsScene extends PixelScene {
if (rowHeight <= 14){
offset = (pos % 2 == 1) ? 5 : -5;
}
- row.setRect( left+offset, top + pos * rowHeight, w - left * 2, rowHeight );
+ row.setRect( insets.left + left+offset, insets.top + top + pos * rowHeight, w - left * 2, rowHeight );
add(row);
pos++;
@@ -121,8 +126,8 @@ public class RankingsScene extends PixelScene {
add( label );
label.setPos(
- (w - label.width()) / 2,
- h - label.height() - 2*GAP
+ insets.left + (w - label.width()) / 2,
+ insets.top + h - label.height() - 2*GAP
);
align(label);
@@ -133,8 +138,8 @@ public class RankingsScene extends PixelScene {
RenderedTextBlock noRec = PixelScene.renderTextBlock(Messages.get(this, "no_games"), 8);
noRec.hardlight( 0xCCCCCC );
noRec.setPos(
- (w - noRec.width()) / 2,
- (h - noRec.height()) / 2
+ insets.left + (w - noRec.width()) / 2,
+ insets.top + (h - noRec.height()) / 2
);
align(noRec);
add(noRec);
@@ -142,10 +147,10 @@ public class RankingsScene extends PixelScene {
}
ExitButton btnExit = new ExitButton();
- btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
+ btnExit.setPos( Camera.main.width - btnExit.width() - insets.right, insets.top );
add( btnExit );
- int left = 0;
+ float left = insets.left;
if (Rankings.INSTANCE.latestDaily != null) {
IconButton btnDailies = new IconButton(Icons.CALENDAR.get()) {
@@ -160,7 +165,7 @@ public class RankingsScene extends PixelScene {
}
};
btnDailies.icon().hardlight(0.5f, 1f, 2f);
- btnDailies.setRect( left, 0, 16, 20 );
+ btnDailies.setRect( left, insets.top, 16, 20 );
left += 16;
add(btnDailies);
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
index 36da38485..9086f0dd7 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
@@ -43,6 +43,7 @@ import com.watabou.noosa.Camera;
import com.watabou.noosa.Game;
import com.watabou.noosa.Image;
import com.watabou.noosa.NinePatch;
+import com.watabou.utils.RectF;
import java.util.ArrayList;
@@ -59,23 +60,27 @@ public class StartScene extends PixelScene {
Journal.loadGlobal();
uiCamera.visible = false;
-
+
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
Archs archs = new Archs();
archs.setSize( w, h );
add( archs );
+
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
ExitButton btnExit = new ExitButton();
- btnExit.setPos( w - btnExit.width(), 0 );
+ btnExit.setPos( insets.left + w - btnExit.width(), insets.top );
add( btnExit );
IconTitle title = new IconTitle( Icons.ENTER.get(), Messages.get(this, "title"));
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
@@ -92,9 +97,9 @@ public class StartScene extends PixelScene {
slotsHeight -= slotCount-1;
}
- float yPos = (h - slotsHeight + title.bottom() + 2)/2f - 4;
+ float yPos = insets.top + (h - slotsHeight + title.bottom() + 2)/2f - 4;
yPos = Math.max(yPos, title.bottom()+2);
- float slotLeft = (w - SLOT_WIDTH) / 2f;
+ float slotLeft = insets.left + (w - SLOT_WIDTH) / 2f;
for (GamesInProgress.Info game : games) {
SaveSlotButton existingGame = new SaveSlotButton();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
index a55493bdb..f7f9213f6 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
@@ -36,6 +36,8 @@ import com.watabou.noosa.Camera;
import com.watabou.noosa.Image;
import com.watabou.noosa.NinePatch;
import com.watabou.noosa.ui.Component;
+import com.watabou.utils.Callback;
+import com.watabou.utils.RectF;
public class SupporterScene extends PixelScene {
@@ -50,6 +52,7 @@ public class SupporterScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
int elementWidth = PixelScene.landscape() ? 202 : 120;
@@ -57,15 +60,18 @@ public class SupporterScene extends PixelScene {
archs.setSize(w, h);
add(archs);
+ w -= insets.right + insets.left;
+ h -= insets.top + insets.bottom;
+
ExitButton btnExit = new ExitButton();
- btnExit.setPos(w - btnExit.width(), 0);
+ btnExit.setPos(insets.left + w - btnExit.width(), insets.top);
add(btnExit);
IconTitle title = new IconTitle(Icons.GOLD.get(), Messages.get(this, "title"));
title.setSize(200, 0);
title.setPos(
- (w - title.reqWidth()) / 2f,
- (20 - title.height()) / 2f
+ insets.left + (w - title.reqWidth()) / 2f,
+ insets.top + (20 - title.height()) / 2f
);
align(title);
add(title);
@@ -93,8 +99,8 @@ public class SupporterScene extends PixelScene {
float elementHeight = msg.height() + BTN_HEIGHT + GAP;
- float top = 16 + (h - 16 - elementHeight)/2f;
- float left = (w-elementWidth)/2f;
+ float top = insets.top + 16 + (h - 16 - elementHeight)/2f;
+ float left = insets.left + (w-elementWidth)/2f;
msg.setPos(left, top);
align(msg);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
index 7bbad82f9..04097f055 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
@@ -56,6 +56,7 @@ import com.watabou.noosa.audio.Music;
import com.watabou.utils.Point;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
+import com.watabou.utils.RectF;
import java.nio.Buffer;
import java.nio.FloatBuffer;
@@ -95,14 +96,19 @@ public class SurfaceScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+
+ RectF insets = getCommonInsets();
Archs archs = new Archs();
archs.reversed = true;
archs.setSize( w, h );
add( archs );
- float vx = align((w - SKY_WIDTH) / 2f);
- float vy = align((h - SKY_HEIGHT - BUTTON_HEIGHT) / 2f);
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
+ float vx = align(insets.left + (w - SKY_WIDTH) / 2f);
+ float vy = align(insets.top + (h - SKY_HEIGHT - BUTTON_HEIGHT) / 2f);
Point s = Camera.main.cameraToScreen( vx, vy );
viewport = new Camera( s.x, s.y, SKY_WIDTH, SKY_HEIGHT, defaultZoom );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
index bb5d5d5be..8788f6d92 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
@@ -52,6 +52,7 @@ import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Music;
import com.watabou.utils.ColorMath;
import com.watabou.utils.DeviceCompat;
+import com.watabou.utils.RectF;
import java.util.Date;
@@ -71,18 +72,23 @@ public class TitleScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
-
+
+ RectF insets = getCommonInsets();
+
Archs archs = new Archs();
archs.setSize( w, h );
add( archs );
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
Image title = BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_LAND : BannerSprites.Type.TITLE_PORT);
add( title );
float topRegion = Math.max(title.height - 6, h*0.45f);
- title.x = (w - title.width()) / 2f;
- title.y = 2 + (topRegion - title.height()) / 2f;
+ title.x = insets.left + (w - title.width()) / 2f;
+ title.y = insets.top + 2 + (topRegion - title.height()) / 2f;
align(title);
@@ -190,9 +196,9 @@ public class TitleScene extends PixelScene {
GAP = Math.max(GAP, 2);
float buttonAreaWidth = landscape() ? PixelScene.MIN_WIDTH_L-6 : PixelScene.MIN_WIDTH_P-2;
- float btnAreaLeft = (Camera.main.width - buttonAreaWidth) / 2f;
+ float btnAreaLeft = insets.left + (w - buttonAreaWidth) / 2f;
if (landscape()) {
- btnPlay.setRect(btnAreaLeft, topRegion+GAP, (buttonAreaWidth/2)-1, BTN_HEIGHT);
+ btnPlay.setRect(btnAreaLeft, insets.top + topRegion+GAP, (buttonAreaWidth/2)-1, BTN_HEIGHT);
align(btnPlay);
btnSupport.setRect(btnPlay.right()+2, btnPlay.top(), btnPlay.width(), BTN_HEIGHT);
btnRankings.setRect(btnPlay.left(), btnPlay.bottom()+ GAP, (float) (Math.floor(buttonAreaWidth/3f)-1), BTN_HEIGHT);
@@ -202,7 +208,7 @@ public class TitleScene extends PixelScene {
btnChanges.setRect(btnSettings.right()+2, btnSettings.top(), btnRankings.width(), BTN_HEIGHT);
btnAbout.setRect(btnChanges.right()+2, btnSettings.top(), btnRankings.width(), BTN_HEIGHT);
} else {
- btnPlay.setRect(btnAreaLeft, topRegion+GAP, buttonAreaWidth, BTN_HEIGHT);
+ btnPlay.setRect(btnAreaLeft, insets.top + topRegion+GAP, buttonAreaWidth, BTN_HEIGHT);
align(btnPlay);
btnSupport.setRect(btnPlay.left(), btnPlay.bottom()+ GAP, btnPlay.width(), BTN_HEIGHT);
btnRankings.setRect(btnPlay.left(), btnSupport.bottom()+ GAP, (btnPlay.width()/2)-1, BTN_HEIGHT);
@@ -216,8 +222,9 @@ public class TitleScene extends PixelScene {
BitmapText version = new BitmapText( "v" + Game.version, pixelFont);
version.measure();
version.hardlight( 0x888888 );
- version.x = w - version.width() - 4;
- version.y = h - version.height() - 2;
+ //TODO perhaps extra check for Android top-right / top-left notches?
+ version.x = insets.left + w - version.width() - 4;
+ version.y = insets.top + h - version.height() - 2;
add( version );
if (DeviceCompat.isDesktop()) {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
index b51daf135..429af253b 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
@@ -48,6 +48,7 @@ import com.watabou.noosa.Game;
import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Music;
import com.watabou.utils.FileUtils;
+import com.watabou.utils.RectF;
import java.util.Collections;
@@ -94,6 +95,7 @@ public class WelcomeScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
+ RectF insets = getCommonInsets();
Archs archs = new Archs();
archs.setSize( w, h );
@@ -102,13 +104,16 @@ public class WelcomeScene extends PixelScene {
//darkens the arches
add(new ColorBlock(w, h, 0x88000000));
+ w -= insets.left + insets.right;
+ h -= insets.top + insets.bottom;
+
Image title = BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_LAND : BannerSprites.Type.TITLE_PORT);
add( title );
float topRegion = Math.max(title.height - 6, h*0.45f);
- title.x = (w - title.width()) / 2f;
- title.y = 2 + (topRegion - title.height()) / 2f;
+ title.x = insets.left + (w - title.width()) / 2f;
+ title.y = insets.top + 2 + (topRegion - title.height()) / 2f;
align(title);
@@ -165,10 +170,10 @@ public class WelcomeScene extends PixelScene {
}
};
- float buttonY = Math.min(topRegion + (PixelScene.landscape() ? 60 : 120), h - 24);
+ float buttonY = insets.top + Math.min(topRegion + (PixelScene.landscape() ? 60 : 120), h - 24);
float buttonAreaWidth = landscape() ? PixelScene.MIN_WIDTH_L-6 : PixelScene.MIN_WIDTH_P-2;
- float btnAreaLeft = (Camera.main.width - buttonAreaWidth) / 2f;
+ float btnAreaLeft = insets.left + (w - buttonAreaWidth) / 2f;
if (previousVersion != 0 && !SPDSettings.intro()){
StyledButton changes = new StyledButton(Chrome.Type.GREY_BUTTON_TR, Messages.get(TitleScene.class, "changes")){
@Override
@@ -216,7 +221,7 @@ public class WelcomeScene extends PixelScene {
text.text(message, Math.min(w-20, 300));
float titleBottom = title.y + title.height();
float textSpace = okay.top() - titleBottom - 4;
- text.setPos((w - text.width()) / 2f, (titleBottom + 2) + (textSpace - text.height())/2);
+ text.setPos(insets.left + (w - text.width()) / 2f, (titleBottom + 2) + (textSpace - text.height())/2);
add(text);
if (SPDSettings.intro() && ControllerHandler.isControllerConnected()){
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Window.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Window.java
index 2f3ceb36a..94694f1f8 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Window.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Window.java
@@ -33,7 +33,9 @@ import com.watabou.noosa.Game;
import com.watabou.noosa.Group;
import com.watabou.noosa.NinePatch;
import com.watabou.noosa.PointerArea;
+import com.watabou.utils.PlatformSupport;
import com.watabou.utils.Point;
+import com.watabou.utils.RectF;
import com.watabou.utils.Signal;
public class Window extends Group implements Signal.Listener {
@@ -94,13 +96,17 @@ public class Window extends Group implements Signal.Listener {
width - chrome.x + chrome.marginRight(),
height - chrome.y + chrome.marginBottom() );
add( chrome );
+
+ RectF insets = Game.platform.getSafeInsets(PlatformSupport.INSET_BLK);
+ int screenW = (int)(Game.width - insets.left - insets.right);
+ int screenH = (int)(Game.height - insets.top - insets.bottom);
camera = new Camera( 0, 0,
(int)chrome.width,
(int)chrome.height,
PixelScene.defaultZoom );
- camera.x = (int)(Game.width - camera.width * camera.zoom) / 2;
- camera.y = (int)(Game.height - camera.height * camera.zoom) / 2;
+ camera.x = (int)(insets.left + (screenW - camera.width * camera.zoom) / 2);
+ camera.y = (int)(insets.top + (screenH - camera.height * camera.zoom) / 2);
camera.y -= yOffset * camera.zoom;
camera.scroll.set( chrome.x, chrome.y );
Camera.add( camera );
@@ -123,10 +129,16 @@ public class Window extends Group implements Signal.Listener {
camera.resize( (int)chrome.width, (int)chrome.height );
- camera.x = (int)(Game.width - camera.screenWidth()) / 2;
+ RectF insets = Game.platform.getSafeInsets(PlatformSupport.INSET_BLK);
+ int screenW = (int)(Game.width - insets.left - insets.right);
+ int screenH = (int)(Game.height - insets.top - insets.bottom);
+
+ camera.x = (int)(screenW - camera.screenWidth()) / 2;
+ camera.x += insets.left;
camera.x += xOffset * camera.zoom;
- camera.y = (int)(Game.height - camera.screenHeight()) / 2;
+ camera.y = (int)(screenH - camera.screenHeight()) / 2;
+ camera.y += insets.top;
camera.y += yOffset * camera.zoom;
shadow.boxRect( camera.x / camera.zoom, camera.y / camera.zoom, chrome.width(), chrome.height );
diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java
index 904cb7a27..007eb6a61 100644
--- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java
+++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java
@@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.watabou.input.ControllerHandler;
import com.watabou.noosa.Game;
import com.watabou.utils.PlatformSupport;
+import com.watabou.utils.RectF;
import org.robovm.apple.audiotoolbox.AudioServices;
import org.robovm.apple.systemconfiguration.SCNetworkReachability;
@@ -63,6 +64,16 @@ public class IOSPlatformSupport extends PlatformSupport {
return false;
}
+ @Override
+ public RectF getSafeInsets(int level) {
+ //TODO currently returns all insets all the time. Needs testing based on particular iOS quirks
+ // we roughly want:
+ // ignore bottom home indicator insets in fullsceen
+ // ignore side insets in landscape for side that isn't notch
+ // older notch is large, compact dynamic island is not (maybe? Probably need UI adjustments then)
+ return super.getSafeInsets(level);
+ }
+
@Override
public void updateSystemUI() {
int prevInset = Game.bottomInset;