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

324 lines
8.2 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.*;
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 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;
root = new BlockContainer(null, small, false);
caret = new Caret(CaretState.VISIBLE_ON, new BlockPosition(root));
}
/**
* 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.inputContext = ic;
this.root = old.root == null ? null : old.root.clone(null, ic);
this.caret = old.caret == null ? null : new Caret(old.caret, root);
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) {
if (root.appendBlock(caret, b)) {
var innerPos = b.getFirstInnerPosition();
caret.setPosition(innerPos == null ? new BlockPosition(b) : innerPos);
root.recomputeDimensions();
}
closeExtra();
}
caretTime = 0;
caret.turnOn();
}
public void typeChar(final String c) {
typeChar(c.charAt(0));
}
public void del() {
var pos = caret.getPos();
BlockOrContainer currentElementToRecompute;
boolean removed;
if (pos.isBlock()) {
var block = pos.getBlock();
var lastInnerPosition = block.getLastInnerPosition();
if (lastInnerPosition != null) {
caret.setPosition(lastInnerPosition);
currentElementToRecompute = null;
removed = false;
} else {
caret.setPosition(pos.getPrevious());
var parent = block.getParentContainer();
parent.removeBlockUnsafe(block);
currentElementToRecompute = parent;
removed = true;
}
} else if (pos.isContainer()) {
var container = pos.getContainer();
if (container == root) {
currentElementToRecompute = null;
removed = false;
} else if (!container.hasParent()) {
throw new IllegalStateException();
} else {
var block = container.getParentBlock();
var containers = block.getInnerContainers();
BlockContainer prevContainer;
if (containers == null) {
prevContainer = null;
} else {
var containerIt = containers.listIterator(containers.indexOf(container));
if (containerIt.hasPrevious()) {
prevContainer = containerIt.previous();
} else {
prevContainer = null;
}
}
if (prevContainer != null) {
var lastPosition = prevContainer.getLastPosition();
caret.setPosition(lastPosition);
currentElementToRecompute = null;
removed = false;
} else {
caret.setPosition(pos.getPrevious());
var parentContainer = block.getParentContainer();
parentContainer.removeBlockUnsafe(block);
currentElementToRecompute = parentContainer;
removed = true;
}
}
} else {
throw new UnsupportedOperationException();
}
if (removed) {
while (currentElementToRecompute != null) {
currentElementToRecompute.recomputeDimensions();
currentElementToRecompute = currentElementToRecompute.getParent();
}
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public BlockReference<?> getSelectedBlock() {
var pos = caret.getPos();
if (pos.isBlock()) {
return pos.getBlock().getReference();
} else {
var container = pos.getContainer();
if (container.hasParent()) {
return container.getParentBlock().getReference();
} else {
return null;
}
}
}
public void moveLeft() {
var prev = caret.getPos().getPrevious();
if (prev != null) {
caret.setPosition(prev);
} else {
caret.setPosition(root.getLastPosition());
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void moveRight() {
var prev = caret.getPos().getNext();
if (prev != null) {
caret.setPosition(prev);
} else {
caret.setPosition(new BlockPosition(root));
}
caret.turnOn();
caretTime = 0;
closeExtra();
}
public void moveTo(final BlockPosition position) {
caret.setPosition(position);
caret.turnOn();
caretTime = 0;
closeExtra();
}
@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) {
root.draw(ge, r, x, y, caret);
if (extra != null) {
extra.draw(ge, r, caret);
}
}
public void clear() {
caret = new Caret(CaretState.VISIBLE_ON, new BlockPosition(root));
root.clear();
recomputeDimensions();
}
public boolean isEmpty() {
return root.getSize() == 0;
}
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);
}
}