324 lines
8.2 KiB
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);
|
|
}
|
|
|
|
}
|