266 lines
6.9 KiB
Java
266 lines
6.9 KiB
Java
/*
|
|
* Pixel Dungeon
|
|
* Copyright (C) 2012-2015 Oleg Dolya
|
|
*
|
|
* Shattered Pixel Dungeon
|
|
* Copyright (C) 2014-2025 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.watabou.noosa;
|
|
|
|
import com.badlogic.gdx.Files;
|
|
import com.badlogic.gdx.Gdx;
|
|
import com.badlogic.gdx.graphics.Mesh;
|
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
|
import com.badlogic.gdx.scenes.scene2d.Stage;
|
|
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
|
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
|
import com.badlogic.gdx.scenes.scene2d.ui.TextArea;
|
|
import com.badlogic.gdx.scenes.scene2d.ui.TextField;
|
|
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
|
import com.badlogic.gdx.utils.Align;
|
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
|
import com.watabou.glscripts.Script;
|
|
import com.watabou.glwrap.Blending;
|
|
import com.watabou.glwrap.Quad;
|
|
import com.watabou.glwrap.Texture;
|
|
import com.watabou.noosa.ui.Component;
|
|
import com.watabou.utils.DeviceCompat;
|
|
import com.watabou.utils.FileUtils;
|
|
import com.watabou.utils.Point;
|
|
|
|
//essentially contains a libGDX text input field, plus a PD-rendered background
|
|
public class TextInput extends Component {
|
|
|
|
private Stage stage;
|
|
private Container container;
|
|
private TextField textField;
|
|
|
|
private Skin skin;
|
|
|
|
private NinePatch bg;
|
|
|
|
public TextInput( NinePatch bg, boolean multiline, int size ){
|
|
super();
|
|
this.bg = bg;
|
|
add(bg);
|
|
|
|
//use a custom viewport here to ensure stage camera matches game camera
|
|
Viewport viewport = new Viewport() {};
|
|
viewport.setWorldSize(Game.width, Game.height);
|
|
viewport.setScreenBounds(0, 0, Game.width, Game.height);
|
|
viewport.setCamera(new OrthographicCamera());
|
|
//TODO this is needed for the moment as Spritebatch switched to using VAOs in libGDX v1.13.1
|
|
// This results in HARD crashes atm, whereas old vertex arrays work fine
|
|
SpriteBatch.overrideVertexType = Mesh.VertexDataType.VertexArray;
|
|
stage = new Stage(viewport);
|
|
Game.inputHandler.addInputProcessor(stage);
|
|
|
|
container = new Container<TextField>();
|
|
stage.addActor(container);
|
|
container.setTransform(true);
|
|
|
|
skin = new Skin(FileUtils.getFileHandle(Files.FileType.Internal, "gdx/textfield.json"));
|
|
|
|
TextField.TextFieldStyle style = skin.get(TextField.TextFieldStyle.class);
|
|
style.font = Game.platform.getFont(size, "", false, false);
|
|
style.background = null;
|
|
if (multiline){
|
|
textField = new TextArea("", style){
|
|
@Override
|
|
public void cut() {
|
|
super.cut();
|
|
onClipBoardUpdate();
|
|
}
|
|
|
|
@Override
|
|
public void copy() {
|
|
super.copy();
|
|
onClipBoardUpdate();
|
|
}
|
|
};
|
|
} else {
|
|
textField = new TextField("", style){
|
|
@Override
|
|
public void cut() {
|
|
super.cut();
|
|
onClipBoardUpdate();
|
|
}
|
|
|
|
@Override
|
|
public void copy() {
|
|
super.copy();
|
|
onClipBoardUpdate();
|
|
}
|
|
};
|
|
}
|
|
textField.setProgrammaticChangeEvents(true);
|
|
|
|
if (!multiline) textField.setAlignment(Align.center);
|
|
|
|
textField.addListener(new ChangeListener() {
|
|
@Override
|
|
public void changed(ChangeEvent event, Actor actor) {
|
|
BitmapFont f = Game.platform.getFont(size, textField.getText(), false, false);
|
|
TextField.TextFieldStyle style = textField.getStyle();
|
|
if (f != style.font){
|
|
style.font = f;
|
|
textField.setStyle(style);
|
|
}
|
|
onChanged();
|
|
}
|
|
});
|
|
|
|
if (!multiline){
|
|
textField.setTextFieldListener(new TextField.TextFieldListener(){
|
|
public void keyTyped (TextField textField, char c){
|
|
if (c == '\r' || c == '\n'){
|
|
enterPressed();
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
textField.setOnscreenKeyboard(new TextField.OnscreenKeyboard() {
|
|
@Override
|
|
public void show(boolean visible) {
|
|
Game.platform.setOnscreenKeyboardVisible(visible, multiline);
|
|
}
|
|
});
|
|
|
|
container.setActor(textField);
|
|
stage.setKeyboardFocus(textField);
|
|
Game.platform.setOnscreenKeyboardVisible(true, multiline);
|
|
}
|
|
|
|
public void enterPressed(){
|
|
//fires any time enter is pressed, do nothing by default
|
|
};
|
|
|
|
public void onChanged(){
|
|
//fires any time the text box is changed, do nothing by default
|
|
}
|
|
|
|
public void onClipBoardUpdate(){
|
|
//fires any time the clipboard is updated via cut or copy, do nothing by default
|
|
}
|
|
|
|
public void setText(String text){
|
|
textField.setText(text);
|
|
textField.setCursorPosition(textField.getText().length());
|
|
}
|
|
|
|
public void setMaxLength(int maxLength){
|
|
textField.setMaxLength(maxLength);
|
|
}
|
|
|
|
public String getText(){
|
|
return textField.getText();
|
|
}
|
|
|
|
public void copyToClipboard(){
|
|
if (textField.getSelection().isEmpty()) {
|
|
textField.selectAll();
|
|
}
|
|
|
|
textField.copy();
|
|
}
|
|
|
|
public void pasteFromClipboard(){
|
|
String contents = Gdx.app.getClipboard().getContents();
|
|
if (contents == null) return;
|
|
|
|
if (!textField.getSelection().isEmpty()){
|
|
//just use cut, but override clipboard
|
|
textField.cut();
|
|
Gdx.app.getClipboard().setContents(contents);
|
|
}
|
|
|
|
String existing = textField.getText();
|
|
int cursorIdx = textField.getCursorPosition();
|
|
|
|
textField.setText(existing.substring(0, cursorIdx) + contents + existing.substring(cursorIdx));
|
|
textField.setCursorPosition(cursorIdx + contents.length());
|
|
}
|
|
|
|
@Override
|
|
protected void layout() {
|
|
super.layout();
|
|
|
|
float contX = x;
|
|
float contY = y;
|
|
float contW = width;
|
|
float contH = height;
|
|
|
|
if (bg != null){
|
|
bg.x = x;
|
|
bg.y = y;
|
|
bg.size(width, height);
|
|
|
|
contX += bg.marginLeft();
|
|
contY += bg.marginTop();
|
|
contW -= bg.marginHor();
|
|
contH -= bg.marginVer();
|
|
}
|
|
|
|
float zoom = Camera.main.zoom;
|
|
Camera c = camera();
|
|
if (c != null){
|
|
zoom = c.zoom;
|
|
Point p = c.cameraToScreen(contX, contY);
|
|
contX = p.x/zoom;
|
|
contY = p.y/zoom;
|
|
}
|
|
|
|
container.align(Align.topLeft);
|
|
container.setPosition(contX*zoom, (Game.height-(contY*zoom)));
|
|
container.size(contW*zoom, contH*zoom);
|
|
}
|
|
|
|
@Override
|
|
public void update() {
|
|
super.update();
|
|
stage.act(Game.elapsed);
|
|
}
|
|
|
|
@Override
|
|
public void draw() {
|
|
super.draw();
|
|
Quad.releaseIndices();
|
|
Script.unuse();
|
|
Texture.clear();
|
|
stage.draw();
|
|
Quad.bindIndices();
|
|
Blending.useDefault();
|
|
}
|
|
|
|
@Override
|
|
public synchronized void destroy() {
|
|
super.destroy();
|
|
if (stage != null) {
|
|
stage.dispose();
|
|
skin.dispose();
|
|
Game.inputHandler.removeInputProcessor(stage);
|
|
Game.platform.setOnscreenKeyboardVisible(false, false);
|
|
if (!DeviceCompat.isDesktop()) Game.platform.updateSystemUI();
|
|
}
|
|
}
|
|
}
|