v1.2.0: implemented full and mixed UI modes, in addition to mobile

This commit is contained in:
Evan Debenham 2022-01-28 16:03:30 -05:00
parent bd79f96630
commit fbbad24e67
8 changed files with 248 additions and 94 deletions

View File

@ -57,11 +57,7 @@ public class Scene extends Group {
public void onResume(){
}
public static boolean landscape(){
return Game.width > Game.height;
}
@Override
public void update() {
super.update();

View File

@ -182,7 +182,9 @@ windows.wndsettings$displaytab.visual_grid=Visual Grid
windows.wndsettings$displaytab.off=Off
windows.wndsettings$displaytab.high=High
windows.wndsettings$uitab.title=Interface Settings
windows.wndsettings$uitab.mode=Toolbar Mode:
windows.wndsettings$uitab.size=Interface Size
windows.wndsettings$uitab.mobile=Mobile
windows.wndsettings$uitab.full=Full
windows.wndsettings$uitab.split=Split
windows.wndsettings$uitab.group=Group
windows.wndsettings$uitab.center=Center

View File

@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.watabou.noosa.Game;
import com.watabou.noosa.audio.Music;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.GameSettings;
import com.watabou.utils.Point;
@ -125,11 +126,30 @@ public class SPDSettings extends GameSettings {
}
//Interface
public static final String KEY_UI_SIZE = "full_ui";
public static final String KEY_QUICKSLOTS = "quickslots";
public static final String KEY_FLIPTOOLBAR = "flipped_ui";
public static final String KEY_FLIPTAGS = "flip_tags";
public static final String KEY_BARMODE = "toolbar_mode";
//0 = mobile, 1 = mixed (large without inventory in main UI), 2 = large
public static void interfaceSize( int value ){
put( KEY_UI_SIZE, value );
}
public static int interfaceSize(){
int size = getInt( KEY_UI_SIZE, DeviceCompat.isDesktop() ? 2 : 0 );
if (size > 0){
//force mobile UI if there is not enough space for full UI
float wMin = Game.width / PixelScene.MIN_WIDTH_FULL;
float hMin = Game.height / PixelScene.MIN_HEIGHT_FULL;
if (Math.min(wMin, hMin) < 2*Game.density){
size = 0;
}
}
return size;
}
public static void quickSlots( int value ){ put( KEY_QUICKSLOTS, value ); }
@ -337,8 +357,8 @@ public class SPDSettings extends GameSettings {
public static Point windowResolution(){
return new Point(
getInt( KEY_WINDOW_WIDTH, 960, 480, Integer.MAX_VALUE ),
getInt( KEY_WINDOW_HEIGHT, 640, 320, Integer.MAX_VALUE )
getInt( KEY_WINDOW_WIDTH, 800, 720, Integer.MAX_VALUE ),
getInt( KEY_WINDOW_HEIGHT, 600, 400, Integer.MAX_VALUE )
);
}

View File

@ -83,6 +83,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
import com.shatteredpixel.shatteredpixeldungeon.ui.CharHealthIndicator;
import com.shatteredpixel.shatteredpixeldungeon.ui.GameLog;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.InventoryPane;
import com.shatteredpixel.shatteredpixeldungeon.ui.LootIndicator;
import com.shatteredpixel.shatteredpixeldungeon.ui.MenuPane;
import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton;
@ -168,7 +169,10 @@ public class GameScene extends PixelScene {
private Group emoicons;
private Group overFogEffects;
private Group healthIndicators;
private InventoryPane inventory;
private static boolean invVisible = true;
private Toolbar toolbar;
private Toast prompt;
@ -349,14 +353,16 @@ public class GameScene extends PixelScene {
add( cellSelector = new CellSelector( tiles ) );
int uiSize = SPDSettings.interfaceSize();
menu = new MenuPane();
menu.camera = uiCamera;
menu.setPos( uiCamera.width-50, 1);
menu.setPos( uiCamera.width-50, uiSize > 0 ? 0 : 1);
add(menu);
status = new StatusPane( false );
status = new StatusPane( SPDSettings.interfaceSize() > 0 );
status.camera = uiCamera;
status.setRect(0, 0, uiCamera.width, 0 );
status.setRect(0, uiSize > 0 ? uiCamera.height-39 : 0, uiCamera.width, 0 );
add(status);
boss = new BossHealthBar();
@ -366,7 +372,17 @@ public class GameScene extends PixelScene {
toolbar = new Toolbar();
toolbar.camera = uiCamera;
toolbar.setRect( 0,uiCamera.height - toolbar.height(), uiCamera.width, toolbar.height() );
if (uiSize == 2) {
inventory = new InventoryPane();
inventory.camera = uiCamera;
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() );
} else {
toolbar.setRect( 0, uiCamera.height - toolbar.height(), uiCamera.width, toolbar.height() );
}
add( toolbar );
attack = new AttackIndicator();
@ -568,7 +584,8 @@ public class GameScene extends PixelScene {
GLog.p(Messages.get(Guidebook.class, "hint"));
GameScene.flashForDocument(Document.GUIDE_DIEING);
}
if (!invVisible) toggleInvPane();
fadeIn();
//re-show WndResurrect if needed
@ -735,13 +752,17 @@ public class GameScene extends PixelScene {
float tagWidth = Tag.SIZE + (tagsOnLeft ? insets.left : insets.right);
float tagLeft = tagsOnLeft ? 0 : uiCamera.width - tagWidth;
if (SPDSettings.flipTags()) {
scene.log.setRect(tagWidth, scene.toolbar.top()-2, uiCamera.width - tagWidth - insets.right, 0);
float y = SPDSettings.interfaceSize() == 0 ? scene.toolbar.top()-2 : scene.status.top()-2;
if (tagsOnLeft) {
scene.log.setRect(tagWidth, y, uiCamera.width - tagWidth - insets.right, 0);
} else {
scene.log.setRect(insets.left, scene.toolbar.top()-2, uiCamera.width - tagWidth - insets.left, 0);
scene.log.setRect(insets.left, y, uiCamera.width - tagWidth - insets.left, 0);
}
float pos = scene.toolbar.top();
if (tagsOnLeft && SPDSettings.interfaceSize() > 0){
pos = scene.status.top();
}
if (scene.tagAttack){
scene.attack.setRect( tagLeft, pos - Tag.SIZE, tagWidth, Tag.SIZE );
@ -1043,6 +1064,19 @@ public class GameScene extends PixelScene {
return false;
}
public static void toggleInvPane(){
if (scene != null && scene.inventory != null){
if (scene.inventory.visible){
scene.inventory.visible = scene.inventory.active = invVisible = false;
scene.toolbar.setPos(scene.toolbar.left(), uiCamera.height-scene.toolbar.height());
} else {
scene.inventory.visible = scene.inventory.active = invVisible = true;
scene.toolbar.setPos(scene.toolbar.left(), scene.inventory.top()-scene.toolbar.height());
}
layoutTags();
}
}
public static void updateFog(){
if (scene != null) {
scene.fog.updateFog();

View File

@ -48,13 +48,20 @@ import java.util.ArrayList;
public class PixelScene extends Scene {
// Minimum virtual display size for portrait orientation
public static final float MIN_WIDTH_P = 135;
public static final float MIN_HEIGHT_P = 225;
// Minimum virtual display size for mobile portrait orientation
public static final float MIN_WIDTH_P = 135;
public static final float MIN_HEIGHT_P = 225;
// Minimum virtual display size for landscape orientation
public static final float MIN_WIDTH_L = 240;
public static final float MIN_HEIGHT_L = 160;
// Minimum virtual display size for mobile landscape orientation
public static final float MIN_WIDTH_L = 240;
public static final float MIN_HEIGHT_L = 160;
// Minimum virtual display size for full desktop UI (landscape only)
//TODO maybe include another scale for mixed UI? might make it more accessible to mobile devices
// mixed UI has similar requirements to mobile landscape tbh... Maybe just merge them?
// mixed UI can possible be used on mobile portrait for tablets though.. Does that happen often?
public static final float MIN_WIDTH_FULL = 360;
public static final float MIN_HEIGHT_FULL = 200;
public static int defaultZoom = 0;
public static int maxDefaultZoom = 0;
@ -82,13 +89,21 @@ public class PixelScene extends Scene {
TextureCache.clear();
}
float minWidth, minHeight;
if (landscape()) {
float minWidth, minHeight, scaleFactor;
if (SPDSettings.interfaceSize() > 0){
minWidth = MIN_WIDTH_FULL;
minHeight = MIN_HEIGHT_FULL;
//TODO not perfect in all cases, especially for big monitors
// Perhaps look at max zoom and increase if default is less than half of max?
scaleFactor = 3.75f;
} else if (landscape()) {
minWidth = MIN_WIDTH_L;
minHeight = MIN_HEIGHT_L;
scaleFactor = 2.5f;
} else {
minWidth = MIN_WIDTH_P;
minHeight = MIN_HEIGHT_P;
scaleFactor = 2.5f;
}
maxDefaultZoom = (int)Math.min(Game.width/minWidth, Game.height/minHeight);
@ -96,7 +111,7 @@ public class PixelScene extends Scene {
defaultZoom = SPDSettings.scale();
if (defaultZoom < Math.ceil( Game.density * 2 ) || defaultZoom > maxDefaultZoom){
defaultZoom = (int)GameMath.gate(2, (int)Math.ceil( Game.density * 2.5 ), maxDefaultZoom);
defaultZoom = (int)GameMath.gate(2, (int)Math.ceil( Game.density * scaleFactor ), maxDefaultZoom);
}
minZoom = 1;
@ -168,6 +183,11 @@ public class PixelScene extends Scene {
PointerEvent.clearListeners();
}
public static boolean landscape(){
return SPDSettings.interfaceSize() > 0 || Game.width > Game.height;
}
public static RenderedTextBlock renderTextBlock(int size ){
return renderTextBlock("", size);
}

View File

@ -147,7 +147,11 @@ public class Toolbar extends Component {
@Override
protected void onClick() {
GameScene.show(new WndBag(Dungeon.hero.belongings.backpack));
if (SPDSettings.interfaceSize() == 2){
GameScene.toggleInvPane();
} else {
GameScene.show(new WndBag(Dungeon.hero.belongings.backpack));
}
}
@Override
@ -181,6 +185,32 @@ public class Toolbar extends Component {
@Override
protected void layout() {
float right = width;
if (SPDSettings.interfaceSize() > 0){
btnInventory.setPos(right - btnInventory.width(), y);
btnWait.setPos(btnInventory.left() - btnWait.width(), y);
btnSearch.setPos(btnWait.left() - btnSearch.width(), y);
right = btnSearch.left();
for(int i = 3; i >= 0; i--) {
if (i == 3){
btnQuick[i].border(0, 2);
btnQuick[i].frame(106, 0, 19, 24);
} else if (i == 0){
btnQuick[i].border(2, 1);
btnQuick[i].frame(86, 0, 20, 24);
} else {
btnQuick[i].border(0, 1);
btnQuick[i].frame(88, 0, 18, 24);
}
btnQuick[i].setPos(right-btnQuick[i].width(), y+2);
right = btnQuick[i].left();
}
return;
}
for(int i = 0; i <= 3; i++) {
if (i == 0 && !SPDSettings.flipToolbar() ||
i == 3 && SPDSettings.flipToolbar()){
@ -196,7 +226,6 @@ public class Toolbar extends Component {
}
}
float right = width;
switch(Mode.valueOf(SPDSettings.toolbarMode())){
case SPLIT:
btnWait.setPos(x, y);

View File

@ -269,12 +269,17 @@ public class WndSettings extends WndTabbed {
}
if (DeviceCompat.isAndroid()) {
btnOrientation = new RedButton(PixelScene.landscape() ?
Boolean landscape = SPDSettings.landscape();
if (landscape == null){
landscape = Game.width > Game.height;
}
Boolean finalLandscape = landscape;
btnOrientation = new RedButton(finalLandscape ?
Messages.get(this, "portrait")
: Messages.get(this, "landscape")) {
@Override
protected void onClick() {
SPDSettings.landscape(!PixelScene.landscape());
SPDSettings.landscape(!finalLandscape);
}
};
add(btnOrientation);
@ -360,7 +365,9 @@ public class WndSettings extends WndTabbed {
private static class UITab extends Component {
RenderedTextBlock title;
ColorBlock sep1;
OptionSlider optUISize;
RenderedTextBlock barDesc;
RedButton btnSplit; RedButton btnGrouped; RedButton btnCentered;
CheckBox chkFlipToolbar;
@ -379,58 +386,84 @@ public class WndSettings extends WndTabbed {
sep1 = new ColorBlock(1, 1, 0xFF000000);
add(sep1);
barDesc = PixelScene.renderTextBlock(Messages.get(this, "mode"), 9);
add(barDesc);
//add slider for UI size only if device has enough space to support it
float wMin = Game.width / PixelScene.MIN_WIDTH_FULL;
float hMin = Game.height / PixelScene.MIN_HEIGHT_FULL;
if (Math.min(wMin, hMin) >= 2*Game.density){
optUISize = new OptionSlider(
Messages.get(this, "size"),
Messages.get(this, "mobile"),
Messages.get(this, "full"),
0,
2
) {
@Override
protected void onChange() {
SPDSettings.interfaceSize(getSelectedValue());
ShatteredPixelDungeon.seamlessResetScene();
}
};
optUISize.setSelectedValue(SPDSettings.interfaceSize());
add(optUISize);
}
btnSplit = new RedButton(Messages.get(this, "split")){
@Override
protected void onClick() {
textColor(TITLE_COLOR);
btnGrouped.textColor(WHITE);
btnCentered.textColor(WHITE);
SPDSettings.toolbarMode(Toolbar.Mode.SPLIT.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.SPLIT.name())) btnSplit.textColor(TITLE_COLOR);
add(btnSplit);
if (SPDSettings.interfaceSize() == 0) {
barDesc = PixelScene.renderTextBlock(Messages.get(this, "mode"), 9);
add(barDesc);
btnGrouped = new RedButton(Messages.get(this, "group")){
@Override
protected void onClick() {
btnSplit.textColor(WHITE);
textColor(TITLE_COLOR);
btnCentered.textColor(WHITE);
SPDSettings.toolbarMode(Toolbar.Mode.GROUP.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.GROUP.name())) btnGrouped.textColor(TITLE_COLOR);
add(btnGrouped);
btnSplit = new RedButton(Messages.get(this, "split")) {
@Override
protected void onClick() {
textColor(TITLE_COLOR);
btnGrouped.textColor(WHITE);
btnCentered.textColor(WHITE);
SPDSettings.toolbarMode(Toolbar.Mode.SPLIT.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.SPLIT.name()))
btnSplit.textColor(TITLE_COLOR);
add(btnSplit);
btnCentered = new RedButton(Messages.get(this, "center")){
@Override
protected void onClick() {
btnSplit.textColor(WHITE);
btnGrouped.textColor(WHITE);
textColor(TITLE_COLOR);
SPDSettings.toolbarMode(Toolbar.Mode.CENTER.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.CENTER.name())) btnCentered.textColor(TITLE_COLOR);
add(btnCentered);
btnGrouped = new RedButton(Messages.get(this, "group")) {
@Override
protected void onClick() {
btnSplit.textColor(WHITE);
textColor(TITLE_COLOR);
btnCentered.textColor(WHITE);
SPDSettings.toolbarMode(Toolbar.Mode.GROUP.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.GROUP.name()))
btnGrouped.textColor(TITLE_COLOR);
add(btnGrouped);
chkFlipToolbar = new CheckBox(Messages.get(this, "flip_toolbar")){
@Override
protected void onClick() {
super.onClick();
SPDSettings.flipToolbar(checked());
Toolbar.updateLayout();
}
};
chkFlipToolbar.checked(SPDSettings.flipToolbar());
add(chkFlipToolbar);
btnCentered = new RedButton(Messages.get(this, "center")) {
@Override
protected void onClick() {
btnSplit.textColor(WHITE);
btnGrouped.textColor(WHITE);
textColor(TITLE_COLOR);
SPDSettings.toolbarMode(Toolbar.Mode.CENTER.name());
Toolbar.updateLayout();
}
};
if (SPDSettings.toolbarMode().equals(Toolbar.Mode.CENTER.name()))
btnCentered.textColor(TITLE_COLOR);
add(btnCentered);
chkFlipToolbar = new CheckBox(Messages.get(this, "flip_toolbar")) {
@Override
protected void onClick() {
super.onClick();
SPDSettings.flipToolbar(checked());
Toolbar.updateLayout();
}
};
chkFlipToolbar.checked(SPDSettings.flipToolbar());
add(chkFlipToolbar);
}
chkFlipTags = new CheckBox(Messages.get(this, "flip_indicators")){
@Override
@ -489,20 +522,31 @@ public class WndSettings extends WndTabbed {
sep1.size(width, 1);
sep1.y = title.bottom() + 2*GAP;
barDesc.setPos((width-barDesc.width())/2f, sep1.y + 1 + GAP);
PixelScene.align(barDesc);
height = sep1.y + 1;
int btnWidth = (int)(width - 2* GAP)/3;
btnSplit.setRect(0, barDesc.bottom() + GAP, btnWidth, 16);
btnGrouped.setRect(btnSplit.right()+ GAP, btnSplit.top(), btnWidth, 16);
btnCentered.setRect(btnGrouped.right()+ GAP, btnSplit.top(), btnWidth, 16);
if (optUISize != null){
optUISize.setRect(0, height + GAP, width, SLIDER_HEIGHT);
height = optUISize.bottom();
}
if (width > 200) {
chkFlipToolbar.setRect(0, btnGrouped.bottom() + GAP, width/2 - 1, BTN_HEIGHT);
chkFlipTags.setRect(chkFlipToolbar.right() + GAP, chkFlipToolbar.top(), width/2 -1, BTN_HEIGHT);
if (barDesc != null) {
barDesc.setPos((width - barDesc.width()) / 2f, height + GAP);
PixelScene.align(barDesc);
int btnWidth = (int) (width - 2 * GAP) / 3;
btnSplit.setRect(0, barDesc.bottom() + GAP, btnWidth, 16);
btnGrouped.setRect(btnSplit.right() + GAP, btnSplit.top(), btnWidth, 16);
btnCentered.setRect(btnGrouped.right() + GAP, btnSplit.top(), btnWidth, 16);
if (width > 200) {
chkFlipToolbar.setRect(0, btnGrouped.bottom() + GAP, width / 2 - 1, BTN_HEIGHT);
chkFlipTags.setRect(chkFlipToolbar.right() + GAP, chkFlipToolbar.top(), width / 2 - 1, BTN_HEIGHT);
} else {
chkFlipToolbar.setRect(0, btnGrouped.bottom() + GAP, width, BTN_HEIGHT);
chkFlipTags.setRect(0, chkFlipToolbar.bottom() + GAP, width, BTN_HEIGHT);
}
} else {
chkFlipToolbar.setRect(0, btnGrouped.bottom() + GAP, width, BTN_HEIGHT);
chkFlipTags.setRect(0, chkFlipToolbar.bottom() + GAP, width, BTN_HEIGHT);
chkFlipTags.setRect(0, height + GAP, width, BTN_HEIGHT);
}
sep2.size(width, 1);
@ -511,9 +555,18 @@ public class WndSettings extends WndTabbed {
chkFont.setRect(0, sep2.y + 1 + GAP, width, BTN_HEIGHT);
if (btnKeyBindings != null){
sep3.size(width, 1);
sep3.y = chkFont.bottom() + 2;
btnKeyBindings.setRect(0, sep3.y + 1 + GAP, width, BTN_HEIGHT);
if (width > 200){
chkFont.setSize(width/2-1, BTN_HEIGHT);
sep3.size(1, BTN_HEIGHT + 2*GAP);
sep3.x = chkFont.right() + 0.5f;
sep3.y = sep2.y+1;
PixelScene.align(sep3);
btnKeyBindings.setRect(chkFont.right()+2, chkFont.top(), width/2 - 1, BTN_HEIGHT);
} else {
sep3.size(width, 1);
sep3.y = chkFont.bottom() + 2;
btnKeyBindings.setRect(0, sep3.y + 1 + GAP, width, BTN_HEIGHT);
}
height = btnKeyBindings.bottom();
} else {
height = chkFont.bottom();

View File

@ -151,7 +151,7 @@ public class DesktopLauncher {
SPDSettings.set( new Lwjgl3Preferences( SPDSettings.DEFAULT_PREFS_FILE, basePath) );
FileUtils.setDefaultFileProperties( Files.FileType.External, basePath );
config.setWindowSizeLimits( 480, 320, -1, -1 );
config.setWindowSizeLimits( 720, 400, -1, -1 );
Point p = SPDSettings.windowResolution();
config.setWindowedMode( p.x, p.y );