WarpPI/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java

303 lines
7.3 KiB
Java

package it.cavallium.warppi.gui.expression.containers;
import it.cavallium.warppi.device.display.DisplayOutputDevice;
import it.cavallium.warppi.event.KeyboardEventListener;
import it.cavallium.warppi.gui.GraphicalElement;
import it.cavallium.warppi.gui.expression.Caret;
import it.cavallium.warppi.gui.expression.CaretState;
import it.cavallium.warppi.gui.expression.ExtraMenu;
import it.cavallium.warppi.gui.expression.InputContext;
import it.cavallium.warppi.gui.expression.blocks.Block;
import it.cavallium.warppi.gui.expression.blocks.BlockContainer;
import it.cavallium.warppi.gui.expression.blocks.BlockDivision;
import it.cavallium.warppi.gui.expression.blocks.BlockReference;
import it.cavallium.warppi.gui.expression.layouts.InputLayout;
import it.cavallium.warppi.gui.graphicengine.Renderer;
import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.util.Error;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class InputContainer implements GraphicalElement, InputLayout {
protected BlockContainer root;
protected Caret caret;
private static final float CARET_DURATION = 0.5f;
private float caretTime;
private int maxPosition = 0;
private boolean parsed = false;
private ExtraMenu<?> extra;
protected InputContext inputContext;
public synchronized InputContext getInputContext() {
return inputContext;
}
@Deprecated()
/**
* Use InputContainer(InputContext) instead
*/
public InputContainer() {
this(new InputContext());
}
public InputContainer(final InputContext ic) {
this(ic, false);
}
public InputContainer(final InputContext ic, final boolean small) {
this(ic, small, 0, 0);
}
public InputContainer(final InputContext ic, final boolean small, final int minWidth, final int minHeight) {
inputContext = ic;
caret = new Caret(CaretState.VISIBLE_ON, 0);
root = new BlockContainer(null, small, false);
}
/**
* Copy
* @param old
* @param ic
*/
protected InputContainer(InputContainer old, InputContext ic) {
this.caretTime = old.caretTime;
this.extra = old.extra == null ? null : old.extra.clone(null, ic);
this.maxPosition = old.maxPosition;
this.caret = old.caret == null ? null : new Caret(old.caret);
this.inputContext = ic;
this.root = old.root == null ? null : old.root.clone(null, ic);
this.parsed = old.parsed;
}
public void typeChar(final char c) {
final Block b = parseChar(c);
typeBlock(b);
}
public void typeBlock(final Block b) {
if (b != null) {
caret.resetRemaining();
// todo: allow blocks to dinamically choose insert mode
var splitAdjacent = b instanceof BlockDivision;
if (root.appendBlock(caret, b, splitAdjacent)) {
caret.setPosition(caret.getPosition() + b.getCaretDeltaPositionAfterCreation());
maxPosition = root.computeCaretMaxBound();
root.recomputeDimensions();
}
closeExtra();
}
caretTime = 0;
caret.turnOn();
}
public void typeChar(final String c) {
typeChar(c.charAt(0));
}
public void del() {
caret.resetRemaining();
if (root.deleteBlock(caret)) {
root.recomputeDimensions();
}
if (caret.getPosition() > 0) {
caret.setPosition(caret.getPosition() - 1);
maxPosition = root.computeCaretMaxBound();
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public BlockReference<?> getSelectedBlock() {
caret.resetRemaining();
final BlockReference<?> selectedBlock = root.getBlock(caret);
return selectedBlock;
}
public BlockReference<?> getBlockAtCaretPosition(final int i) {
final BlockReference<?> selectedBlock = root.getBlock(new Caret(CaretState.HIDDEN, i));
return selectedBlock;
}
public void moveLeft() {
final int curPos = caret.getPosition();
if (curPos > 0) {
caret.setPosition(curPos - 1);
} else {
caret.setPosition(maxPosition - 1);
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void moveRight(final int delta) {
final int curPos = caret.getPosition();
if (curPos + delta < maxPosition) {
caret.setPosition(curPos + delta);
} else {
caret.setPosition(0);
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void moveTo(final int position) {
if (position < maxPosition) {
caret.setPosition(position);
} else {
caret.setPosition(0);
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void moveRight() {
moveRight(1);
}
@Override
public void recomputeDimensions() {
root.recomputeDimensions();
}
@Override
public int getWidth() {
return root.getWidth();
}
@Override
public int getHeight() {
return root.getHeight();
}
@Override
public int getLine() {
return root.getLine();
}
/**
*
* @param delta
* Time, in seconds
* @return true if something changed
*/
public boolean beforeRender(final float delta) {
boolean somethingChanged = false;
caretTime += delta;
if (caretTime >= InputContainer.CARET_DURATION) {
while (caretTime >= InputContainer.CARET_DURATION) {
caretTime -= InputContainer.CARET_DURATION;
caret.flipState();
somethingChanged = true;
}
}
if (extra != null) {
somethingChanged = somethingChanged | extra.beforeRender(delta, caret);
}
return somethingChanged;
}
/**
*
* @param ge
* Graphic Engine class.
* @param r
* Graphic Renderer class of <b>ge</b>.
* @param x
* Position relative to the window.
* @param y
* Position relative to the window.
*/
public void draw(final DisplayOutputDevice ge, final Renderer r, final int x, final int y) {
caret.resetRemaining();
root.draw(ge, r, x, y, caret);
if (extra != null) {
extra.draw(ge, r, caret);
}
}
public void clear() {
caret = new Caret(CaretState.VISIBLE_ON, 0);
root.clear();
maxPosition = root.computeCaretMaxBound();
recomputeDimensions();
}
public boolean isEmpty() {
return maxPosition <= 1;
}
public int getCaretMaxPosition() {
return maxPosition;
}
public void setCaretPosition(final int pos) {
if (pos > 0 && pos < maxPosition) {
caret.setPosition(pos);
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void setParsed(final boolean parsed) {
this.parsed = parsed;
}
public boolean isAlreadyParsed() {
return parsed;
}
/**
* <strong>WARNING! DO NOT MODIFY THIS ARRAY!!!</strong>
*
* @return an arraylist representing the content
*/
public ObjectArrayList<Block> getContent() {
return root.getContent();
}
public void toggleExtra() {
if (extra == null) {
final BlockReference<?> selectedBlock = getSelectedBlock();
if (selectedBlock != null) {
extra = selectedBlock.get().getExtraMenu();
if (extra != null) {
extra.open();
}
}
} else {
extra.close();
extra = null;
}
}
public void closeExtra() {
if (extra != null) {
extra.close();
extra = null;
}
}
public boolean isExtraOpened() {
return extra != null;
}
public KeyboardEventListener getExtraKeyboardEventListener() {
return extra;
}
public Function toFunction(final MathContext context) throws Error {
return root.toFunction(context);
}
}