/* * Pixel Dungeon * Copyright (C) 2012-2015 Oleg Dolya * * Shattered Pixel Dungeon * Copyright (C) 2014-2019 Evan Debenham * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ package com.shatteredpixel.shatteredpixeldungeon.windows; import com.badlogic.gdx.Input; import com.shatteredpixel.shatteredpixeldungeon.input.GameAction; import com.shatteredpixel.shatteredpixeldungeon.input.PDInputProcessor; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.watabou.input.NoosaInputProcessor; import com.watabou.noosa.BitmapText; import com.watabou.noosa.Game; import com.watabou.noosa.ui.Component; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; public class WndKeymap extends Window { private static final int MARGIN = 0; private static final float ITEM_HEIGHT = 12; private static final int BTN_HEIGHT = 20; public static final String TXT_UNASSIGNED = "<None>"; private Component listContent; private int tempPos = 0; private final Map<GameAction, ListItem> items = new HashMap<>(32); private static class KeyPair { public int key1, key2; } public WndKeymap() { int ww = Math.min( 160, PixelScene.uiCamera.width - 16 ); int wh = PixelScene.uiCamera.height - 24; resize( ww, wh ); RedButton btnReset = new RedButton( "Reset To Defaults" ) { @Override protected void onClick() { resetToDefaults(); populateList(); } }; btnReset.setRect( 0, height - BTN_HEIGHT, width, BTN_HEIGHT ); add( btnReset ); listContent = new Component(); final ScrollPane list = new ScrollPane(listContent) { @Override public void onClick( float x, float y ) { for (ListItem item : items.values()) { if (item.onClick( x, y )) { break; } } } }; populateList(); add(list); list.setRect(0, 0, width, btnReset.top() ); } private void populateList() { listContent.clear(); tempPos = 0; final PDInputProcessor inputProcessor = (PDInputProcessor) Game.instance.getInputProcessor(); final Map<Integer, PDInputProcessor.GameActionWrapper> keyMappings = inputProcessor.getKeyMappings(); final Map<GameAction, KeyPair> mappings = new TreeMap<>(); for (GameAction action : GameAction.values()) { if (action.getDescription() != null) { mappings.put( action, new KeyPair() ); } } for (Map.Entry<Integer, PDInputProcessor.GameActionWrapper> entry : keyMappings.entrySet()) { final Integer key = entry.getKey(); final PDInputProcessor.GameActionWrapper value = entry.getValue(); final GameAction action = value.gameAction; final KeyPair keyPair = mappings.get(action); /* if (keyPair == null) { mappings.put(action, keyPair = new KeyPair()); }*/ if (value.defaultKey) { keyPair.key1 = key; } else { keyPair.key2 = key; } } for (Map.Entry<GameAction, KeyPair> entry : mappings.entrySet()) { addKey(listContent, width, entry); } listContent.setSize( 0, tempPos); } private void addKey(Component content, int maxWidth, Map.Entry<GameAction, KeyPair> entry) { final GameAction action = entry.getKey(); final ListItem keyItem = new ListItem(action, entry.getValue()); keyItem.setRect(0, tempPos, maxWidth, ITEM_HEIGHT); tempPos += ITEM_HEIGHT; content.add(keyItem); items.put(action, keyItem); } private void resetToDefaults() { ((PDInputProcessor)Game.instance.getInputProcessor()).resetKeyMappings(); } private class ListItem extends Component { private static final int BOUND = TITLE_COLOR; private static final int NOT_BOUND = 0xCACFC2; private final GameAction gameAction; private final KeyPair keys; private RenderedTextBlock action; private RenderedTextBlock key1; private RenderedTextBlock key2; public ListItem( GameAction gameAction, KeyPair keys ) { super(); this.gameAction = gameAction; this.keys = keys; action.text(gameAction.getDescription()); //action.measure(); reconfigureKeysText(); } @Override protected void createChildren() { action = PixelScene.renderTextBlock( 9 ); add( action ); key1 = PixelScene.renderTextBlock( 9 ); add( key1 ); key2 = PixelScene.renderTextBlock( 9 ); add( key2 ); } @Override protected void layout() { final float ty = y + (height - action.height()) / 2; final float w4 = width / 4; action.setPos( MARGIN, ty ); key1.setPos( w4 * 2 + (w4 - key1.width()) / 2, ty ); key2.setPos( w4 * 3 + (w4 - key2.width()) / 2, ty ); } private void reconfigureKeysText() { if (keys.key1 > 0) { key1.text( Input.Keys.toString( keys.key1 ) ); key1.hardlight( BOUND ); } else { key1.text( TXT_UNASSIGNED ); key1.hardlight( NOT_BOUND ); } //key1.measure(); if (keys.key2 > 0) { key2.text( Input.Keys.toString( keys.key2 ) ); key2.hardlight( BOUND ); } else { key2.text( TXT_UNASSIGNED ); key2.hardlight( NOT_BOUND ); } //key2.measure(); layout(); } public int getKey(boolean defaultKey) { if (defaultKey) { return this.keys.key1; } else { return this.keys.key2; } } public void setKey(boolean defaultKey, int keycode) { if (defaultKey) { this.keys.key1 = keycode; } else { this.keys.key2 = keycode; } reconfigureKeysText(); } public boolean onClick( float x, float y ) { if (x < this.x || x > this.x + width || y < this.y || y > this.y + height) { return false; } final boolean defaultKey = x < width * 3 / 4; final String message = "Press a key for \"" + gameAction.getDescription() + "\", or press " + Input.Keys.toString(PDInputProcessor.MODIFIER_KEY) + " to remove the binding."; Game.scene().add( new WndMessage( message ) { @Override protected void onKeyDown( NoosaInputProcessor.Key key ) { final PDInputProcessor inputProcessor = (PDInputProcessor) Game.instance.getInputProcessor(); final Map<Integer, PDInputProcessor.GameActionWrapper> keyMappings = inputProcessor.getKeyMappings(); int oldKeycode = getKey(defaultKey); inputProcessor.removeKeyMapping( gameAction, defaultKey, oldKeycode); // Don't allow the modifier key to be replaced. TODO: This should probably be improved if (key.code == PDInputProcessor.MODIFIER_KEY) { setKey(defaultKey, 0); } else { setKey(defaultKey, key.code); final PDInputProcessor.GameActionWrapper replacedAction = inputProcessor.setKeyMapping( gameAction, defaultKey, key.code); if (replacedAction != null) { final ListItem replacedItem = items.get(replacedAction.gameAction); replacedItem.setKey(replacedAction.defaultKey, 0); } } hide(); } } ); return true; } } }