From 1add7aa5d5c2d872bc82186b8e080e72748620e2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 1 Jun 2022 15:54:58 -0400 Subject: [PATCH] v1.3.0: expanded and restructured the settings menu --- .../com/watabou/input/ControllerHandler.java | 5 + core/src/main/assets/interfaces/icons.png | Bin 14630 -> 14678 bytes .../messages/windows/windows.properties | 12 +- .../shatteredpixeldungeon/SPDSettings.java | 43 +- .../scenes/CellSelector.java | 26 +- .../scenes/PixelScene.java | 16 +- .../shatteredpixeldungeon/ui/Icons.java | 26 +- .../ui/OptionSlider.java | 5 + .../windows/WndSettings.java | 451 +++++++++++++----- 9 files changed, 426 insertions(+), 158 deletions(-) diff --git a/SPD-classes/src/main/java/com/watabou/input/ControllerHandler.java b/SPD-classes/src/main/java/com/watabou/input/ControllerHandler.java index 6b71b677a..9bc5202d1 100644 --- a/SPD-classes/src/main/java/com/watabou/input/ControllerHandler.java +++ b/SPD-classes/src/main/java/com/watabou/input/ControllerHandler.java @@ -26,6 +26,7 @@ import com.badlogic.gdx.Input; import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.controllers.ControllerListener; import com.badlogic.gdx.controllers.ControllerMapping; +import com.badlogic.gdx.controllers.Controllers; import com.watabou.utils.DeviceCompat; import com.watabou.utils.PointF; @@ -60,6 +61,10 @@ public class ControllerHandler implements ControllerListener { } } + public static boolean isControllerConnected(){ + return controllersSupported() && Controllers.getCurrent() != null; + } + @Override public void connected(Controller controller) { setControllerType(controller); diff --git a/core/src/main/assets/interfaces/icons.png b/core/src/main/assets/interfaces/icons.png index 6835e9314e1f33b00885be747eb6d7b03fb7c27c..fe84d4aa2fd04170a2bc066a0960c685ded1e2e9 100644 GIT binary patch literal 14678 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 literal 14630 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 diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index 20cae1e16..5202ccdc0 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -206,7 +206,6 @@ windows.wndsettings$displaytab.okay=Okay windows.wndsettings$displaytab.cancel=Cancel windows.wndsettings$displaytab.portrait=Switch to portrait windows.wndsettings$displaytab.landscape=Switch to landscape -windows.wndsettings$displaytab.scale=Display Scale windows.wndsettings$displaytab.brightness=Brightness windows.wndsettings$displaytab.dark=Dark windows.wndsettings$displaytab.bright=Bright @@ -214,9 +213,11 @@ 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.size=Interface Size +windows.wndsettings$uitab.ui_mode=Interface Mode +windows.wndsettings$uitab.scale=Interface Scale windows.wndsettings$uitab.mobile=Mobile windows.wndsettings$uitab.full=Full +windows.wndsettings$uitab.toolbar_settings=Toolbar Settings windows.wndsettings$uitab.mode=Toolbar Mode: windows.wndsettings$uitab.split=Split windows.wndsettings$uitab.group=Group @@ -226,6 +227,13 @@ windows.wndsettings$uitab.flip_indicators=Flip Indicators windows.wndsettings$uitab.quickslots=Quickslots windows.wndsettings$uitab.system_font=System Font windows.wndsettings$uitab.key_bindings=Key Bindings +windows.wndsettings$inputtab.title=Input Settings +windows.wndsettings$inputtab.key_bindings=Key Bindings +windows.wndsettings$inputtab.controller_bindings=Controller Bindings +windows.wndsettings$inputtab.controller_sensitivity=Controller Pointer Sensitivity +windows.wndsettings$inputtab.movement_sensitivity=Hold To Move Sensitivity +windows.wndsettings$inputtab.off=Off +windows.wndsettings$inputtab.high=High windows.wndsettings$datatab.title=Connectivity Settings windows.wndsettings$datatab.news=Check for news windows.wndsettings$datatab.updates=Check for updates diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java index e5946ad95..ea465f3af 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java @@ -48,12 +48,11 @@ public class SPDSettings extends GameSettings { return getInt( KEY_VERSION, 0 ); } - //Graphics + //Display public static final String KEY_FULLSCREEN = "fullscreen"; public static final String KEY_LANDSCAPE = "landscape"; public static final String KEY_POWER_SAVER = "power_saver"; - public static final String KEY_SCALE = "scale"; public static final String KEY_ZOOM = "zoom"; public static final String KEY_BRIGHTNESS = "brightness"; public static final String KEY_GRID = "visual_grid"; @@ -92,14 +91,6 @@ public class SPDSettings extends GameSettings { return getBoolean( KEY_POWER_SAVER, false ); } - public static void scale( int value ) { - put( KEY_SCALE, value ); - } - - public static int scale() { - return getInt( KEY_SCALE, 0 ); - } - public static void zoom( int value ) { put( KEY_ZOOM, value ); } @@ -129,6 +120,7 @@ public class SPDSettings extends GameSettings { //Interface public static final String KEY_UI_SIZE = "full_ui"; + public static final String KEY_SCALE = "scale"; public static final String KEY_QUICKSLOTS = "quickslots"; public static final String KEY_FLIPTOOLBAR = "flipped_ui"; public static final String KEY_FLIPTAGS = "flip_tags"; @@ -151,6 +143,14 @@ public class SPDSettings extends GameSettings { } return size; } + + public static void scale( int value ) { + put( KEY_SCALE, value ); + } + + public static int scale() { + return getInt( KEY_SCALE, 0 ); + } public static void quickSlots( int value ){ put( KEY_QUICKSLOTS, value ); } @@ -224,7 +224,28 @@ public class SPDSettings extends GameSettings { public static boolean supportNagged() { return getBoolean(KEY_SUPPORT_NAGGED, false); } - + + //Input + + public static final String KEY_CONTROLLER_SENS = "controller_sens"; + public static final String KEY_MOVE_SENS = "move_sens"; + + public static void controllerPointerSensitivity( int value ){ + put( KEY_CONTROLLER_SENS, value ); + } + + public static int controllerPointerSensitivity(){ + return getInt(KEY_CONTROLLER_SENS, 5, 1, 10); + } + + public static void movementHoldSensitivity( int value ){ + put( KEY_MOVE_SENS, value ); + } + + public static int movementHoldSensitivity(){ + return getInt(KEY_MOVE_SENS, 3, 0, 4); + } + //Audio public static final String KEY_MUSIC = "music"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java index ad68be218..83550984c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java @@ -251,10 +251,24 @@ public class CellSelector extends ScrollArea { private GameAction heldAction3 = SPDAction.NONE; private float heldDelay = 0f; - //note that delay starts ticking down on the frame it is processed - // so in most cases the actual wait is 50-58ms - private static final float INITIAL_DELAY = 0.06f; private boolean delayingForRelease = false; + + private static float initialDelay(){ + switch (SPDSettings.movementHoldSensitivity()){ + case 0: + return Float.POSITIVE_INFINITY; + case 1: + return 0.13f; + case 2: + return 0.09f; + //note that delay starts ticking down on the frame it is processed + // so in most cases the actual default wait is 50-58ms + case 3: default: + return 0.06f; + case 4: + return 0.03f; + } + } private Signal.Listener keyListener = new Signal.Listener() { @Override @@ -307,7 +321,7 @@ public class CellSelector extends ScrollArea { delayingForRelease = true; //in case more keys are being released //note that this delay can tick down while the hero is moving - heldDelay = INITIAL_DELAY; + heldDelay = initialDelay(); } } else if (directionFromAction(action) != 0) { @@ -316,7 +330,7 @@ public class CellSelector extends ScrollArea { lastCellMoved = -1; if (heldAction1 == SPDAction.NONE){ heldAction1 = action; - heldDelay = INITIAL_DELAY; + heldDelay = initialDelay(); delayingForRelease = false; } else if (heldAction2 == SPDAction.NONE){ heldAction2 = action; @@ -349,7 +363,7 @@ public class CellSelector extends ScrollArea { if (newLeftStick != leftStickAction){ if (leftStickAction == SPDAction.NONE){ - heldDelay = INITIAL_DELAY; + heldDelay = initialDelay(); Dungeon.hero.resting = false; } else if (newLeftStick == SPDAction.NONE && heldDelay > 0f){ heldDelay = 0f; 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 78f9bc0ee..fc2f968d6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java @@ -172,9 +172,19 @@ public class PixelScene extends Scene { ControllerHandler.setControllerPointer(true); virtualCursorPos = PointerEvent.currentHoverPos(); } - //cursor moves 500 scaled pixels per second at full speed, 100 at minimum speed - virtualCursorPos.x += defaultZoom * 500 * Game.elapsed * ControllerHandler.rightStickPosition.x; - virtualCursorPos.y += defaultZoom * 500 * Game.elapsed * ControllerHandler.rightStickPosition.y; + + int sensitivity = SPDSettings.controllerPointerSensitivity() * 100; + + //cursor moves 100xsens scaled pixels per second at full speed + //35x at 50% movement, ~9x at 20% deadzone threshold + float xMove = (float)Math.pow(Math.abs(ControllerHandler.rightStickPosition.x), 1.5); + if (ControllerHandler.rightStickPosition.x < 0) xMove = -xMove; + + float yMove = (float)Math.pow(Math.abs(ControllerHandler.rightStickPosition.y), 1.5); + if (ControllerHandler.rightStickPosition.y < 0) yMove = -yMove; + + virtualCursorPos.x += defaultZoom * sensitivity * Game.elapsed * xMove; + virtualCursorPos.y += defaultZoom * sensitivity * Game.elapsed * yMove; virtualCursorPos.x = GameMath.gate(0, virtualCursorPos.x, Game.width); virtualCursorPos.y = GameMath.gate(0, virtualCursorPos.y, Game.height); PointerEvent.addPointerEvent(new PointerEvent((int) virtualCursorPos.x, (int) virtualCursorPos.y, 10_000, PointerEvent.Type.HOVER, PointerEvent.NONE)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java index 6eda55445..be55daf5d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java @@ -56,6 +56,7 @@ public enum Icons { AUDIO, LANGS, CONTROLLER, + KEYBOARD, STATS, CHALLENGE_OFF, CHALLENGE_ON, @@ -179,7 +180,7 @@ public enum Icons { icon.frame( icon.texture.uvRectBySize( 32, 32, 16, 12 ) ); break; case DATA: - icon.frame( icon.texture.uvRectBySize( 48, 32, 16, 15 ) ); + icon.frame( icon.texture.uvRectBySize( 48, 32, 14, 15 ) ); break; case AUDIO: icon.frame( icon.texture.uvRectBySize( 64, 32, 14, 14 ) ); @@ -190,29 +191,32 @@ public enum Icons { case CONTROLLER: icon.frame( icon.texture.uvRectBySize( 96, 32, 16, 12 ) ); break; + case KEYBOARD: + icon.frame( icon.texture.uvRectBySize( 112, 32, 15, 12 ) ); + break; case STATS: - icon.frame( icon.texture.uvRectBySize( 112, 32, 16, 13 ) ); + icon.frame( icon.texture.uvRectBySize( 128, 32, 16, 13 ) ); break; case CHALLENGE_OFF: - icon.frame( icon.texture.uvRectBySize( 128, 32, 14, 12 ) ); - break; - case CHALLENGE_ON: icon.frame( icon.texture.uvRectBySize( 144, 32, 14, 12 ) ); break; - case RENAME_OFF: - icon.frame( icon.texture.uvRectBySize( 160, 32, 15, 14 ) ); + case CHALLENGE_ON: + icon.frame( icon.texture.uvRectBySize( 160, 32, 14, 12 ) ); break; - case RENAME_ON: + case RENAME_OFF: icon.frame( icon.texture.uvRectBySize( 176, 32, 15, 14 ) ); break; + case RENAME_ON: + icon.frame( icon.texture.uvRectBySize( 192, 32, 15, 14 ) ); + break; case SEED: - icon.frame( icon.texture.uvRectBySize( 192, 32, 10, 10 ) ); + icon.frame( icon.texture.uvRectBySize( 208, 32, 10, 10 ) ); break; case LEFTARROW: - icon.frame( icon.texture.uvRectBySize( 208, 32, 14, 8 ) ); + icon.frame( icon.texture.uvRectBySize( 224, 32, 14, 8 ) ); break; case RIGHTARROW: - icon.frame( icon.texture.uvRectBySize( 224, 32, 14, 8 ) ); + icon.frame( icon.texture.uvRectBySize( 240, 32, 14, 8 ) ); break; case UNCHECKED: diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/OptionSlider.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/OptionSlider.java index b28fafa37..40ea67973 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/OptionSlider.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/OptionSlider.java @@ -60,6 +60,11 @@ public abstract class OptionSlider extends Component { active = false; } + if (title.length() > 20){ + remove(this.title); + this.title = PixelScene.renderTextBlock(6); + add(this.title); + } this.title.text(title); this.minTxt.text(minTxt); this.maxTxt.text(maxTxt); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java index 1cb55717d..6b64a2d5c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java @@ -40,8 +40,10 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.Toolbar; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; +import com.watabou.input.ControllerHandler; import com.watabou.noosa.ColorBlock; import com.watabou.noosa.Game; +import com.watabou.noosa.Image; import com.watabou.noosa.audio.Sample; import com.watabou.noosa.ui.Component; import com.watabou.utils.DeviceCompat; @@ -56,12 +58,13 @@ public class WndSettings extends WndTabbed { private static final int WIDTH_P = 122; private static final int WIDTH_L = 223; - private static final int SLIDER_HEIGHT = 24; - private static final int BTN_HEIGHT = 18; + private static final int SLIDER_HEIGHT = 23; + private static final int BTN_HEIGHT = 17; private static final float GAP = 2; private DisplayTab display; private UITab ui; + private InputTab input; private DataTab data; private AudioTab audio; private LangsTab langs; @@ -103,6 +106,28 @@ public class WndSettings extends WndTabbed { } }); + input = new InputTab(); + input.setSize(width, 0); + height = Math.max(height, input.height()); + + if (DeviceCompat.hasHardKeyboard() || ControllerHandler.isControllerConnected()) { + add( input ); + Image icon; + if (ControllerHandler.controllerPointerActive() || !DeviceCompat.hasHardKeyboard()){ + icon = Icons.get(Icons.CONTROLLER); + } else { + icon = Icons.get(Icons.KEYBOARD); + } + add(new IconTab(icon) { + @Override + protected void select(boolean value) { + super.select(value); + input.visible = input.active = value; + if (value) last_index = 2; + } + }); + } + data = new DataTab(); data.setSize(width, 0); height = Math.max(height, data.height()); @@ -113,7 +138,7 @@ public class WndSettings extends WndTabbed { protected void select(boolean value) { super.select(value); data.visible = data.active = value; - if (value) last_index = 2; + if (value) last_index = 3; } }); @@ -127,7 +152,7 @@ public class WndSettings extends WndTabbed { protected void select(boolean value) { super.select(value); audio.visible = audio.active = value; - if (value) last_index = 3; + if (value) last_index = 4; } }); @@ -142,7 +167,7 @@ public class WndSettings extends WndTabbed { protected void select(boolean value) { super.select(value); langs.visible = langs.active = value; - if (value) last_index = 4; + if (value) last_index = 5; } @Override @@ -165,7 +190,12 @@ public class WndSettings extends WndTabbed { layoutTabs(); - select(last_index); + if (tabs.size() == 5 && last_index >= 3){ + //input tab isn't visible + select(last_index-1); + } else { + select(last_index); + } } @@ -221,7 +251,7 @@ public class WndSettings extends WndTabbed { } add(chkFullscreen); - if ((int)Math.ceil(2* Game.density) < PixelScene.maxDefaultZoom) { + /*if ((int)Math.ceil(2* Game.density) < PixelScene.maxDefaultZoom) { optScale = new OptionSlider(Messages.get(this, "scale"), (int)Math.ceil(2* Game.density)+ "X", PixelScene.maxDefaultZoom + "X", @@ -237,7 +267,7 @@ public class WndSettings extends WndTabbed { }; optScale.setSelectedValue(PixelScene.defaultZoom); add(optScale); - } + }*/ if (DeviceCompat.isAndroid() && PixelScene.maxScreenZoom >= 2) { chkSaver = new CheckBox(Messages.get(this, "saver")) { @@ -367,10 +397,9 @@ public class WndSettings extends WndTabbed { RenderedTextBlock title; ColorBlock sep1; - OptionSlider optUISize; - RenderedTextBlock barDesc; - RedButton btnSplit; RedButton btnGrouped; RedButton btnCentered; - CheckBox chkFlipToolbar; + OptionSlider optUIMode; + OptionSlider optUIScale; + RedButton btnToolbarSettings; CheckBox chkFlipTags; ColorBlock sep2; CheckBox chkFont; @@ -390,8 +419,8 @@ public class WndSettings extends WndTabbed { 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"), + optUIMode = new OptionSlider( + Messages.get(this, "ui_mode"), Messages.get(this, "mobile"), Messages.get(this, "full"), 0, @@ -403,78 +432,152 @@ public class WndSettings extends WndTabbed { ShatteredPixelDungeon.seamlessResetScene(); } }; - optUISize.setSelectedValue(SPDSettings.interfaceSize()); - add(optUISize); + optUIMode.setSelectedValue(SPDSettings.interfaceSize()); + add(optUIMode); + } + + if ((int)Math.ceil(2* Game.density) < PixelScene.maxDefaultZoom) { + optUIScale = new OptionSlider(Messages.get(this, "scale"), + (int)Math.ceil(2* Game.density)+ "X", + PixelScene.maxDefaultZoom + "X", + (int)Math.ceil(2* Game.density), + PixelScene.maxDefaultZoom ) { + @Override + protected void onChange() { + if (getSelectedValue() != SPDSettings.scale()) { + SPDSettings.scale(getSelectedValue()); + ShatteredPixelDungeon.seamlessResetScene(); + } + } + }; + optUIScale.setSelectedValue(PixelScene.defaultZoom); + add(optUIScale); } if (SPDSettings.interfaceSize() == 0) { - barDesc = PixelScene.renderTextBlock(Messages.get(this, "mode"), 9); - add(barDesc); - - btnSplit = new RedButton(Messages.get(this, "split")) { + btnToolbarSettings = new RedButton(Messages.get(this, "toolbar_settings"), 9){ @Override protected void onClick() { - textColor(TITLE_COLOR); - btnGrouped.textColor(WHITE); - btnCentered.textColor(WHITE); - SPDSettings.toolbarMode(Toolbar.Mode.SPLIT.name()); - Toolbar.updateLayout(); + ShatteredPixelDungeon.scene().addToFront(new Window(){ + + RenderedTextBlock barDesc; + RedButton btnSplit; RedButton btnGrouped; RedButton btnCentered; + CheckBox chkFlipToolbar; + CheckBox chkFlipTags; + //TODO checkbox for forcing 6 quicksltos on mobile portrait + + { + barDesc = PixelScene.renderTextBlock(Messages.get(WndSettings.UITab.this, "mode"), 9); + add(barDesc); + + btnSplit = new RedButton(Messages.get(WndSettings.UITab.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); + + btnGrouped = new RedButton(Messages.get(WndSettings.UITab.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); + + btnCentered = new RedButton(Messages.get(WndSettings.UITab.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(WndSettings.UITab.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(WndSettings.UITab.this, "flip_indicators")){ + @Override + protected void onClick() { + super.onClick(); + SPDSettings.flipTags(checked()); + GameScene.layoutTags(); + } + }; + chkFlipTags.checked(SPDSettings.flipTags()); + add(chkFlipTags); + + //layout + resize(WIDTH_P, 0); + + barDesc.setPos((width - barDesc.width()) / 2f, GAP); + PixelScene.align(barDesc); + + int btnWidth = (int) (width - 2 * GAP) / 3; + btnSplit.setRect(0, barDesc.bottom() + GAP, btnWidth, BTN_HEIGHT-2); + btnGrouped.setRect(btnSplit.right() + GAP, btnSplit.top(), btnWidth, BTN_HEIGHT-2); + btnCentered.setRect(btnGrouped.right() + GAP, btnSplit.top(), btnWidth, BTN_HEIGHT-2); + + 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); + } + + resize(WIDTH_P, (int)chkFlipTags.bottom()); + + } + }); } }; - if (SPDSettings.toolbarMode().equals(Toolbar.Mode.SPLIT.name())) - btnSplit.textColor(TITLE_COLOR); - add(btnSplit); + add(btnToolbarSettings); - 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); + } else { - 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")) { + chkFlipTags = new CheckBox(Messages.get(this, "flip_indicators")) { @Override protected void onClick() { super.onClick(); - SPDSettings.flipToolbar(checked()); - Toolbar.updateLayout(); + SPDSettings.flipTags(checked()); + GameScene.layoutTags(); } }; - chkFlipToolbar.checked(SPDSettings.flipToolbar()); - add(chkFlipToolbar); - } + chkFlipTags.checked(SPDSettings.flipTags()); + add(chkFlipTags); - chkFlipTags = new CheckBox(Messages.get(this, "flip_indicators")){ - @Override - protected void onClick() { - super.onClick(); - SPDSettings.flipTags(checked()); - GameScene.layoutTags(); - } - }; - chkFlipTags.checked(SPDSettings.flipTags()); - add(chkFlipTags); + } sep2 = new ColorBlock(1, 1, 0xFF000000); add(sep2); @@ -498,22 +601,6 @@ public class WndSettings extends WndTabbed { }; chkFont.checked(SPDSettings.systemFont()); add(chkFont); - - if (DeviceCompat.hasHardKeyboard()){ - - sep3 = new ColorBlock(1, 1, 0xFF000000); - add(sep3); - - btnKeyBindings = new RedButton(Messages.get(this, "key_bindings")){ - @Override - protected void onClick() { - super.onClick(); - ShatteredPixelDungeon.scene().addToFront(new WndKeyBindings()); - } - }; - - add(btnKeyBindings); - } } @Override @@ -524,33 +611,32 @@ public class WndSettings extends WndTabbed { height = sep1.y + 1; - if (optUISize != null){ - optUISize.setRect(0, height + GAP, width, SLIDER_HEIGHT); - height = optUISize.bottom(); + if (optUIMode != null && optUIScale != null && width > 200){ + optUIMode.setRect(0, height + GAP, width/2-1, SLIDER_HEIGHT); + optUIScale.setRect(width/2+1, height + GAP, width/2-1, SLIDER_HEIGHT); + height = optUIScale.bottom(); + } else { + if (optUIMode != null) { + optUIMode.setRect(0, height + GAP, width, SLIDER_HEIGHT); + height = optUIMode.bottom(); + } + + if (optUIScale != null) { + optUIScale.setRect(0, height + GAP, width, SLIDER_HEIGHT); + height = optUIScale.bottom(); + } } - 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); - } + if (btnToolbarSettings != null) { + btnToolbarSettings.setRect(0, height + GAP, width, BTN_HEIGHT); + height = btnToolbarSettings.bottom(); } else { chkFlipTags.setRect(0, height + GAP, width, BTN_HEIGHT); + height = chkFlipTags.bottom(); } sep2.size(width, 1); - sep2.y = chkFlipTags.bottom() + 2; + sep2.y = height + 2; chkFont.setRect(0, sep2.y + 1 + GAP, width, BTN_HEIGHT); @@ -575,6 +661,128 @@ public class WndSettings extends WndTabbed { } + private static class InputTab extends Component{ + + RenderedTextBlock title; + ColorBlock sep1; + + RedButton btnKeyBindings; + RedButton btnControllerBindings; + + ColorBlock sep2; + + OptionSlider optControlSens; + OptionSlider optHoldMoveSens; + + @Override + protected void createChildren() { + title = PixelScene.renderTextBlock(Messages.get(this, "title"), 9); + title.hardlight(TITLE_COLOR); + add(title); + + sep1 = new ColorBlock(1, 1, 0xFF000000); + add(sep1); + + if (DeviceCompat.hasHardKeyboard()){ + + btnKeyBindings = new RedButton(Messages.get(this, "key_bindings")){ + @Override + protected void onClick() { + super.onClick(); + ShatteredPixelDungeon.scene().addToFront(new WndKeyBindings()); + } + }; + + add(btnKeyBindings); + } + + if (ControllerHandler.isControllerConnected()){ + btnControllerBindings = new RedButton(Messages.get(this, "controller_bindings")){ + @Override + protected void onClick() { + super.onClick(); + //TODO Controller bindings menu + } + }; + + add(btnControllerBindings); + } + + sep2 = new ColorBlock(1, 1, 0xFF000000); + add(sep2); + + + optControlSens = new OptionSlider( + Messages.get(this, "controller_sensitivity"), + "1", + "10", + 1, + 10 + ) { + @Override + protected void onChange() { + SPDSettings.controllerPointerSensitivity(getSelectedValue()); + } + }; + optControlSens.setSelectedValue(SPDSettings.controllerPointerSensitivity()); + add(optControlSens); + + optHoldMoveSens = new OptionSlider( + Messages.get(this, "movement_sensitivity"), + Messages.get(this, "off"), + Messages.get(this, "high"), + 0, + 4 + ) { + @Override + protected void onChange() { + SPDSettings.movementHoldSensitivity(getSelectedValue()); + } + }; + optHoldMoveSens.setSelectedValue(SPDSettings.movementHoldSensitivity()); + add(optHoldMoveSens); + } + + @Override + protected void layout() { + title.setPos((width - title.width())/2, y + GAP); + sep1.size(width, 1); + sep1.y = title.bottom() + 2*GAP; + + height = sep1.y+1; + + if (width > 200 && btnKeyBindings != null && btnControllerBindings != null){ + btnKeyBindings.setRect(0, height + GAP, width/2-1, BTN_HEIGHT); + btnControllerBindings.setRect(width/2+1, height + GAP, width/2-1, BTN_HEIGHT); + height = btnControllerBindings.bottom(); + } else { + if (btnKeyBindings != null) { + btnKeyBindings.setRect(0, height + GAP, width, BTN_HEIGHT); + height = btnKeyBindings.bottom(); + } + + if (btnControllerBindings != null) { + btnControllerBindings.setRect(0, height + GAP, width, BTN_HEIGHT); + height = btnControllerBindings.bottom(); + } + } + + sep2.size(width, 1); + sep2.y = height+ GAP; + + if (width > 200){ + optControlSens.setRect(0, sep2.y + 1 + GAP, width/2-1, SLIDER_HEIGHT); + optHoldMoveSens.setRect(width/2 + 1, optControlSens.top(), width/2 -1, SLIDER_HEIGHT); + } else { + optControlSens.setRect(0, sep2.y + 1 + GAP, width, SLIDER_HEIGHT); + optHoldMoveSens.setRect(0, optControlSens.bottom() + GAP, width, SLIDER_HEIGHT); + } + + height = optHoldMoveSens.bottom(); + + } + } + private static class DataTab extends Component{ RenderedTextBlock title; @@ -811,13 +1019,12 @@ public class WndSettings extends WndTabbed { private static class LangsTab extends Component{ final static int COLS_P = 3; - final static int COLS_L = 4; + final static int COLS_L = 6; final static int BTN_HEIGHT = 11; RenderedTextBlock title; ColorBlock sep1; - RenderedTextBlock txtLangName; RenderedTextBlock txtLangInfo; ColorBlock sep2; RedButton[] lanBtns; @@ -843,17 +1050,14 @@ public class WndSettings extends WndTabbed { final Languages currLang = Messages.lang(); - txtLangName = PixelScene.renderTextBlock( Messages.titleCase(currLang.nativeName()) , 9 ); - if (currLang.status() == Languages.Status.REVIEWED) txtLangName.hardlight(TITLE_COLOR); - else if (currLang.status() == Languages.Status.UNREVIEWED) txtLangName.hardlight(CharSprite.WARNING); - else if (currLang.status() == Languages.Status.INCOMPLETE) txtLangName.hardlight(CharSprite.NEGATIVE); - add(txtLangName); - txtLangInfo = PixelScene.renderTextBlock(6); - if (currLang == Languages.ENGLISH) txtLangInfo.text("This is the source language, written by the developer."); - else if (currLang.status() == Languages.Status.REVIEWED) txtLangInfo.text(Messages.get(this, "completed")); - else if (currLang.status() == Languages.Status.UNREVIEWED) txtLangInfo.text(Messages.get(this, "unreviewed")); - else if (currLang.status() == Languages.Status.INCOMPLETE) txtLangInfo.text(Messages.get(this, "unfinished")); + String info = "_" + Messages.titleCase(currLang.nativeName()) + "_ - "; + if (currLang == Languages.ENGLISH) info += "This is the source language, written by the developer."; + else if (currLang.status() == Languages.Status.REVIEWED) info += Messages.get(this, "completed"); + else if (currLang.status() == Languages.Status.UNREVIEWED) info += Messages.get(this, "unreviewed"); + else if (currLang.status() == Languages.Status.INCOMPLETE) info += Messages.get(this, "unfinished"); + txtLangInfo.text(info); + if (currLang.status() == Languages.Status.UNREVIEWED) txtLangInfo.setHightlighting(true, CharSprite.WARNING); else if (currLang.status() == Languages.Status.INCOMPLETE) txtLangInfo.setHightlighting(true, CharSprite.NEGATIVE); add(txtLangInfo); @@ -864,7 +1068,7 @@ public class WndSettings extends WndTabbed { lanBtns = new RedButton[langs.size()]; for (int i = 0; i < langs.size(); i++){ final int langIndex = i; - RedButton btn = new RedButton(Messages.titleCase(langs.get(i).nativeName()), 8){ + RedButton btn = new RedButton(Messages.titleCase(langs.get(i).nativeName()), 7){ @Override protected void onClick() { super.onClick(); @@ -902,7 +1106,7 @@ public class WndSettings extends WndTabbed { sep3 = new ColorBlock(1, 1, 0xFF000000); add(sep3); - txtTranifex = PixelScene.renderTextBlock(6); + txtTranifex = PixelScene.renderTextBlock(5); txtTranifex.text(Messages.get(this, "transifex")); add(txtTranifex); @@ -995,10 +1199,7 @@ public class WndSettings extends WndTabbed { sep1.size(width, 1); sep1.y = title.bottom() + 2*GAP; - txtLangName.setPos( (width - txtLangName.width())/2f, sep1.y + 1 + GAP ); - PixelScene.align(txtLangName); - - txtLangInfo.setPos(0, txtLangName.bottom() + 2*GAP); + txtLangInfo.setPos(0, sep1.y + 1 + GAP); txtLangInfo.maxWidth((int)width); y = txtLangInfo.bottom() + GAP;