Refactor caret positioning

This commit is contained in:
Andrea Cavalli 2023-08-23 16:47:55 +02:00
parent 3031966145
commit 7ae4315837
24 changed files with 622 additions and 512 deletions

View File

@ -50,7 +50,13 @@
<artifactId>flow-nbt</artifactId> <artifactId>flow-nbt</artifactId>
<version>1.0.1-SNAPSHOT</version> <version>1.0.1-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>

View File

@ -1,23 +1,28 @@
package it.cavallium.warppi.gui.expression; package it.cavallium.warppi.gui.expression;
import it.cavallium.warppi.gui.expression.blocks.BlockContainer;
import it.cavallium.warppi.gui.expression.blocks.BlockOrContainer;
import it.cavallium.warppi.gui.expression.blocks.BlockPosition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.util.Arrays;
public class Caret { public class Caret {
private int pos; @NotNull
private int remaining; private BlockPosition pos;
private CaretState state; private CaretState state;
private final int[] lastSize; private final int[] lastSize;
private final int[] lastLocation; private final int[] lastLocation;
public Caret(final CaretState state, final int pos) { public Caret(final CaretState state, final BlockPosition pos) {
this(state, pos, new int[] { 0, 0 }, new int[] { 2, 5 }); this(state, pos, new int[] { 0, 0 }, new int[] { 2, 5 });
} }
public Caret(final CaretState state, final int pos, final int[] lastLocation, final int[] lastSize) { public Caret(final CaretState state, final @NotNull BlockPosition pos, final int[] lastLocation, final int[] lastSize) {
this.state = state; this.state = state;
this.pos = pos; this.pos = pos;
remaining = pos;
this.lastLocation = lastLocation; this.lastLocation = lastLocation;
this.lastSize = lastSize; this.lastSize = lastSize;
} }
@ -26,26 +31,27 @@ public class Caret {
* Copy * Copy
* @param old * @param old
*/ */
public Caret(Caret old) { public Caret(Caret old, BlockContainer newRoot) {
this.pos = old.pos; this.pos = clonePosition(old.pos, newRoot);
this.remaining = old.remaining;
this.state = old.state; this.state = old.state;
this.lastSize = Arrays.copyOf(old.lastSize, old.lastSize.length); this.lastSize = Arrays.copyOf(old.lastSize, old.lastSize.length);
this.lastLocation = Arrays.copyOf(old.lastLocation, old.lastLocation.length); this.lastLocation = Arrays.copyOf(old.lastLocation, old.lastLocation.length);
} }
public void skip(final int i) { private BlockPosition clonePosition(BlockPosition pos, BlockContainer newRoot) {
remaining -= i; BlockOrContainer el = newRoot;
var url = pos.getURL();
for (int i : url) {
el = el.getAt(i);
}
return new BlockPosition(el);
} }
public int getPosition() { @NotNull
public BlockPosition getPos() {
return pos; return pos;
} }
public int getRemaining() {
return remaining;
}
public CaretState getState() { public CaretState getState() {
return state; return state;
} }
@ -64,12 +70,8 @@ public class Caret {
} }
} }
public void setPosition(final int i) { public void setPosition(final BlockPosition pos) {
pos = i; this.pos = pos;
}
public void resetRemaining() {
remaining = pos;
} }
public void setLastLocation(final int x, final int y) { public void setLastLocation(final int x, final int y) {
@ -90,4 +92,7 @@ public class Caret {
return new int[] { lastSize[0], lastSize[1] }; return new int[] { lastSize[0], lastSize[1] };
} }
public boolean isHere(BlockOrContainer pos) {
return getPos().get() == pos;
}
} }

View File

@ -5,6 +5,7 @@ import java.util.Arrays;
import it.cavallium.warppi.device.display.DisplayOutputDevice; import it.cavallium.warppi.device.display.DisplayOutputDevice;
import it.cavallium.warppi.event.KeyboardEventListener; import it.cavallium.warppi.event.KeyboardEventListener;
import it.cavallium.warppi.gui.expression.blocks.Block; import it.cavallium.warppi.gui.expression.blocks.Block;
import it.cavallium.warppi.gui.expression.blocks.BlockContainer;
import it.cavallium.warppi.gui.expression.blocks.BlockVariable; import it.cavallium.warppi.gui.expression.blocks.BlockVariable;
import it.cavallium.warppi.gui.expression.blocks.TreeContainer; import it.cavallium.warppi.gui.expression.blocks.TreeContainer;
import it.cavallium.warppi.gui.graphicengine.Renderer; import it.cavallium.warppi.gui.graphicengine.Renderer;
@ -46,7 +47,7 @@ public abstract class ExtraMenu<T extends Block> implements KeyboardEventListene
return false; return false;
} }
public abstract ExtraMenu<T> clone(final TreeContainer parent, InputContext ic); public abstract ExtraMenu<T> clone(final BlockContainer parent, InputContext ic);
public abstract ExtraMenu<T> clone(T newBlockVariable); public abstract ExtraMenu<T> clone(T newBlockVariable);

View File

@ -11,13 +11,13 @@ import it.cavallium.warppi.math.parser.features.interfaces.Feature;
import it.cavallium.warppi.util.Error; import it.cavallium.warppi.util.Error;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class Block implements TreeBlock, GraphicalElement { public abstract class Block implements TreeBlock, BlockOrContainer, GraphicalElement {
protected boolean small; protected boolean small;
protected int width; protected int width;
protected int height; protected int height;
protected int line; protected int line;
protected TreeContainer parent; protected BlockContainer parent;
public Block() { public Block() {
@ -27,7 +27,7 @@ public abstract class Block implements TreeBlock, GraphicalElement {
* Copy * Copy
* @param b * @param b
*/ */
public Block(TreeContainer parent, Block b) { public Block(BlockContainer parent, Block b) {
this.small = b.small; this.small = b.small;
this.width = b.width; this.width = b.width;
this.height = b.height; this.height = b.height;
@ -43,15 +43,10 @@ public abstract class Block implements TreeBlock, GraphicalElement {
* Position relative to the window. * Position relative to the window.
* @param y * @param y
* Position relative to the window. * Position relative to the window.
* @param small
*/ */
public abstract void draw(DisplayOutputDevice ge, Renderer r, int x, int y, Caret caret); public abstract void draw(DisplayOutputDevice ge, Renderer r, int x, int y, Caret caret);
public abstract boolean appendBlock(Caret caret, Block newBlock, boolean splitAdjacent); public abstract boolean appendBlock(Caret caret, Block newBlock);
public abstract boolean deleteBlock(Caret caret);
public abstract BlockReference<?> getBlock(Caret caret);
/** /**
* Used only to get inner blocks when deleting the parent block. * Used only to get inner blocks when deleting the parent block.
@ -64,8 +59,6 @@ public abstract class Block implements TreeBlock, GraphicalElement {
@Override @Override
public abstract void recomputeDimensions(); public abstract void recomputeDimensions();
public abstract int computeCaretMaxBound();
@Override @Override
public int getWidth() { public int getWidth() {
return width; return width;
@ -81,10 +74,6 @@ public abstract class Block implements TreeBlock, GraphicalElement {
return line; return line;
} }
public int getCaretDeltaPositionAfterCreation() {
return 1;
}
public boolean isSmall() { public boolean isSmall() {
return small; return small;
} }
@ -98,18 +87,66 @@ public abstract class Block implements TreeBlock, GraphicalElement {
public abstract Feature toFeature(MathContext context) throws Error; public abstract Feature toFeature(MathContext context) throws Error;
@Override @Override
public TreeContainer getParentContainer() { public BlockContainer getParentContainer() {
return parent; return parent;
} }
@Override
public BlockContainer getParent() {
return parent;
}
@Override
public BlockOrContainer getAt(int index) {
var ic = getInnerContainers();
return ic.get(index);
}
@Override
public int getIndex() {
return parent != null ? parent.getContentUnsafe().indexOf(this) : -1;
}
@Override @Override
public boolean hasParent() { public boolean hasParent() {
return parent != null; return parent != null;
} }
public void setParent(final TreeContainer parent) { public void setParent(final BlockContainer parent) {
this.parent = parent; this.parent = parent;
} }
public abstract Block clone(TreeContainer parent, InputContext ic); public abstract Block clone(BlockContainer parent, InputContext ic);
public BlockReference<?> getReference() {
if (this.hasParent()) {
return this.parent.getReference(this);
} else {
return null;
}
}
public BlockPosition getLastInnerPosition() {
var innerContainers = getInnerContainers();
if (innerContainers != null && !innerContainers.isEmpty()) {
var lastContainer = innerContainers.get(innerContainers.size() - 1);
var content = lastContainer.getContent();
if (content.isEmpty()) {
return new BlockPosition(lastContainer);
} else {
return new BlockPosition(content.get(content.size() - 1));
}
} else {
return null;
}
}
public BlockPosition getFirstInnerPosition() {
var innerContainers = getInnerContainers();
if (innerContainers != null && !innerContainers.isEmpty()) {
return new BlockPosition(innerContainers.get(0));
} else {
return null;
}
}
} }

View File

@ -23,7 +23,7 @@ public class BlockChar extends Block {
* @param b * @param b
* @param ic * @param ic
*/ */
protected BlockChar(final TreeContainer parent, final BlockChar b, InputContext ic) { protected BlockChar(final BlockContainer parent, final BlockChar b, InputContext ic) {
super(parent, b); super(parent, b);
this.ch = b.ch; this.ch = b.ch;
} }
@ -36,20 +36,10 @@ public class BlockChar extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
return false; return false;
} }
@Override
public boolean deleteBlock(final Caret caret) {
return false;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return null;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
width = BlockContainer.getDefaultCharWidth(small) - 1; width = BlockContainer.getDefaultCharWidth(small) - 1;
@ -67,11 +57,6 @@ public class BlockChar extends Block {
return ch; return ch;
} }
@Override
public int computeCaretMaxBound() {
return 0;
}
@Override @Override
public Feature toFeature(final MathContext context) { public Feature toFeature(final MathContext context) {
return new FeatureChar(getChar()); return new FeatureChar(getChar());
@ -88,7 +73,7 @@ public class BlockChar extends Block {
} }
@Override @Override
public BlockChar clone(final TreeContainer parent, InputContext ic) { public BlockChar clone(final BlockContainer parent, InputContext ic) {
return new BlockChar(parent, this, ic); return new BlockChar(parent, this, ic);
} }

View File

@ -15,9 +15,8 @@ import it.cavallium.warppi.math.parser.features.interfaces.Feature;
import it.cavallium.warppi.util.Error; import it.cavallium.warppi.util.Error;
import it.cavallium.warppi.util.Errors; import it.cavallium.warppi.util.Errors;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
public class BlockContainer implements TreeContainer, GraphicalElement { public class BlockContainer implements TreeContainer, BlockOrContainer, GraphicalElement {
private static boolean initialized = false; private static boolean initialized = false;
@ -30,39 +29,39 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
private int line; private int line;
public final boolean withBorder; public final boolean withBorder;
private boolean autoMinimums; private boolean autoMinimums;
private final TreeBlock parent; private final Block parent;
public BlockContainer() { public BlockContainer() {
this(null, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true); this(null, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true);
autoMinimums = true; autoMinimums = true;
} }
public BlockContainer(final TreeBlock parent) { public BlockContainer(final Block parent) {
this(parent, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true); this(parent, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true);
autoMinimums = true; autoMinimums = true;
} }
public BlockContainer(final TreeBlock parent, final boolean small) { public BlockContainer(final Block parent, final boolean small) {
this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true); this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true);
autoMinimums = true; autoMinimums = true;
} }
public BlockContainer(final TreeBlock parent, final boolean small, final ObjectArrayList<Block> content) { public BlockContainer(final Block parent, final boolean small, final ObjectArrayList<Block> content) {
this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), content, true); this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), content, true);
autoMinimums = true; autoMinimums = true;
} }
public BlockContainer(final TreeBlock parent, final boolean small, final boolean withBorder) { public BlockContainer(final Block parent, final boolean small, final boolean withBorder) {
this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder); this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder);
autoMinimums = true; autoMinimums = true;
} }
public BlockContainer(final TreeBlock parent, final boolean small, final int minWidth, final int minHeight, final boolean withBorder) { public BlockContainer(final Block parent, final boolean small, final int minWidth, final int minHeight, final boolean withBorder) {
this(parent, small, minWidth, minHeight, new ObjectArrayList<>(), withBorder); this(parent, small, minWidth, minHeight, new ObjectArrayList<>(), withBorder);
autoMinimums = false; autoMinimums = false;
} }
public BlockContainer(final TreeBlock parent, final boolean small, final int minWidth, final int minHeight, final ObjectArrayList<Block> content, final boolean withBorder) { public BlockContainer(final Block parent, final boolean small, final int minWidth, final int minHeight, final ObjectArrayList<Block> content, final boolean withBorder) {
this.parent = parent; this.parent = parent;
this.small = small; this.small = small;
this.minWidth = minWidth; this.minWidth = minWidth;
@ -77,7 +76,7 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
recomputeDimensions(); recomputeDimensions();
} }
private BlockContainer(final TreeBlock parent, BlockContainer old, InputContext ic) { private BlockContainer(final Block parent, BlockContainer old, InputContext ic) {
this.autoMinimums = old.autoMinimums; this.autoMinimums = old.autoMinimums;
this.content = new ObjectArrayList<>(); this.content = new ObjectArrayList<>();
for (Block b : old.content) { for (Block b : old.content) {
@ -94,15 +93,30 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
this.withBorder = old.withBorder; this.withBorder = old.withBorder;
} }
public BlockContainer clone(final TreeBlock parent, InputContext ic) { public BlockContainer clone(final Block parent, InputContext ic) {
return new BlockContainer(parent, this, ic); return new BlockContainer(parent, this, ic);
} }
@Override @Override
public TreeBlock getParentBlock() { public Block getParentBlock() {
return parent; return parent;
} }
@Override
public Block getParent() {
return parent;
}
@Override
public BlockOrContainer getAt(int index) {
return content.get(index);
}
@Override
public int getIndex() {
return parent != null ? parent.getInnerContainers().indexOf(this) : -1;
}
@Override @Override
public boolean hasParent() { public boolean hasParent() {
return parent != null; return parent != null;
@ -155,7 +169,7 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
public BlockReference<?> getBlockAt(final int i) { public BlockReference<?> getBlockAt(final int i) {
final Block b = content.get(i); final Block b = content.get(i);
return new BlockReference<>(b, i, this); return new BlockReference<>(b, i, content, this);
} }
public int getSize() { public int getSize() {
@ -183,7 +197,7 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
public void draw(final DisplayOutputDevice ge, final Renderer r, final int x, final int y, final Caret caret) { public void draw(final DisplayOutputDevice ge, final Renderer r, final int x, final int y, final Caret caret) {
int paddingX = 1; int paddingX = 1;
if (caret.getRemaining() == 0) { if (caret.isHere(this)) {
if (content.size() > 0) { if (content.size() > 0) {
BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height); BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height);
} else { } else {
@ -199,113 +213,39 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
r.glDrawLine(x + paddingX, y + height - 1, x + paddingX + width - 1, y + height - 1); r.glDrawLine(x + paddingX, y + height - 1, x + paddingX + width - 1, y + height - 1);
} else { } else {
for (final Block b : content) { for (final Block b : content) {
caret.skip(1);
b.draw(ge, r, x + paddingX, y + line - b.line, caret); b.draw(ge, r, x + paddingX, y + line - b.line, caret);
paddingX += b.getWidth(); paddingX += b.getWidth();
if (caret.getRemaining() == 0) { if (caret.isHere(b)) {
BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height); BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height);
} }
paddingX += 1; paddingX += 1;
} }
} }
caret.skip(1);
} }
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
if (caret.getRemaining() == 0) { if (caret.isHere(this)) {
addBlock(0, newBlock); addBlock(0, newBlock);
added = true; added = true;
} }
int pos = 0; int pos = 0;
for (final Block b : content) { for (final Block b : content) {
caret.skip(1);
pos++; pos++;
added = added | b.appendBlock(caret, newBlock, splitAdjacent); added = added | b.appendBlock(caret, newBlock);
if (caret.getRemaining() == 0) { if (caret.isHere(b)) {
addBlock(pos, newBlock); addBlock(pos, newBlock);
added = true; added = true;
} }
} }
caret.skip(1);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
int pos = 0;
for (final Block b : content) {
caret.skip(1);
pos++;
final int deltaCaret = caret.getRemaining();
final int caretOldPos = caret.getPosition();
removed = removed | b.deleteBlock(caret);
if (caret.getRemaining() == 0 || removed == false && deltaCaret >= 0 && caret.getRemaining() < 0) {
ObjectArrayList<Block> blocks = this.getBlockAt(pos - 1).get().getInnerBlocks();
ObjectArrayList<BlockContainer> innerContainers = this.getBlockAt(pos - 1).get().getInnerContainers();
int innerContainersBeforeCaret = 0;
int currentBlockIndex = 0;
if (innerContainers != null) {
for (BlockContainer c : innerContainers) {
currentBlockIndex += c.computeCaretMaxBound();
if (currentBlockIndex > deltaCaret) {
break;
}
innerContainersBeforeCaret++;
}
}
// If the caret is at the end of a block with inner containers don't delete anything and enter into that block.
if (innerContainers == null || (innerContainers.size() - innerContainersBeforeCaret != 0)) {
removeAt(pos - 1);
if (blocks != null) {
ObjectListIterator<Block> blocksIterator = blocks.iterator();
int blockNum = 0;
while (blocksIterator.hasNext()) {
Block block = blocksIterator.next();
addBlockUnsafe(pos - 1 + blockNum, block);
blockNum++;
}
}
caret.setPosition(caretOldPos - innerContainersBeforeCaret);
removed = true;
}
}
}
caret.skip(1);
if (removed) {
recomputeDimensions();
}
return removed;
}
public BlockReference<?> getBlock(final Caret caret) {
BlockReference<?> block = null;
int pos = 0;
for (final Block b : content) {
caret.skip(1);
pos++;
final int deltaCaret = caret.getRemaining();
block = b.getBlock(caret);
if (block != null) {
return block;
}
if (caret.getRemaining() == 0 || deltaCaret >= 0 && caret.getRemaining() < 0) {
block = getBlockAt(pos - 1);
return block;
}
}
caret.skip(1);
return block;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
int l = 0; //Line int l = 0; //Line
@ -430,14 +370,6 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
} }
} }
public int computeCaretMaxBound() {
int maxpos = 0;
for (final Block b : content) {
maxpos += 1 + b.computeCaretMaxBound();
}
return maxpos + 1;
}
public Function toFunction(final MathContext context) throws Error { public Function toFunction(final MathContext context) throws Error {
final ObjectArrayList<Block> blocks = getContent(); final ObjectArrayList<Block> blocks = getContent();
final ObjectArrayList<Feature> blockFeatures = new ObjectArrayList<>(); final ObjectArrayList<Feature> blockFeatures = new ObjectArrayList<>();
@ -454,4 +386,22 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
return result; return result;
} }
public <T extends Block> BlockReference<T> getReference(T block) {
var i = content.indexOf(block);
if (i < 0) return null;
return new BlockReference<>(block, i, content, this);
}
public ObjectArrayList<Block> getContentUnsafe() {
return content;
}
public Block getLastBlock() {
return content.isEmpty() ? null : content.get(content.size() - 1);
}
public BlockPosition getLastPosition() {
var lastBlock = getLastBlock();
return lastBlock != null ? new BlockPosition(lastBlock) : new BlockPosition(this);
}
} }

View File

@ -19,14 +19,19 @@ public class BlockDivision extends Block {
private int paddingLeftUpper; private int paddingLeftUpper;
private int paddingLeftLower; private int paddingLeftLower;
private int h1; private int h1;
private ObjectArrayList<BlockContainer> innerContainers;
public BlockDivision() { public BlockDivision() {
containerUp = new BlockContainer(this, false); containerUp = new BlockContainer(this, false);
containerDown = new BlockContainer(this, false); containerDown = new BlockContainer(this, false);
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(2);
innerContainers.add(containerUp);
innerContainers.add(containerDown);
} }
private BlockDivision(final TreeContainer parent, BlockDivision old, InputContext ic) { private BlockDivision(final BlockContainer parent, BlockDivision old, InputContext ic) {
super(parent, old); super(parent, old);
containerUp = old.containerUp.clone(this, ic); containerUp = old.containerUp.clone(this, ic);
containerDown = old.containerDown.clone(this, ic); containerDown = old.containerDown.clone(this, ic);
@ -34,6 +39,10 @@ public class BlockDivision extends Block {
paddingLeftUpper = old.paddingLeftUpper; paddingLeftUpper = old.paddingLeftUpper;
h1 = old.h1; h1 = old.h1;
System.out.println(String.join(",", ""+h1, ""+old.h1, ""+line, ""+old.line)); System.out.println(String.join(",", ""+h1, ""+old.h1, ""+line, ""+old.line));
innerContainers = new ObjectArrayList<>(2);
innerContainers.add(containerUp);
innerContainers.add(containerDown);
} }
@Override @Override
@ -47,38 +56,16 @@ public class BlockDivision extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerUp.appendBlock(caret, newBlock, splitAdjacent); added = added | containerUp.appendBlock(caret, newBlock);
added = added | containerDown.appendBlock(caret, newBlock, splitAdjacent); added = added | containerDown.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
removed = removed | containerUp.deleteBlock(caret);
removed = removed | containerDown.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
BlockReference<?> bl = null;
bl = containerUp.getBlock(caret);
if (bl != null) {
return bl;
}
bl = containerDown.getBlock(caret);
return bl;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
final int w1 = containerUp.getWidth(); final int w1 = containerUp.getWidth();
@ -119,11 +106,6 @@ public class BlockDivision extends Block {
return containerDown; return containerDown;
} }
@Override
public int computeCaretMaxBound() {
return containerUp.computeCaretMaxBound() + containerDown.computeCaretMaxBound();
}
@Override @Override
public Feature toFeature(final MathContext context) throws Error { public Feature toFeature(final MathContext context) throws Error {
final Function upper = getUpperContainer().toFunction(context); final Function upper = getUpperContainer().toFunction(context);
@ -140,14 +122,11 @@ public class BlockDivision extends Block {
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public ObjectArrayList<BlockContainer> getInnerContainers() {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>(); return innerContainers;
output.add(containerUp);
output.add(containerDown);
return output;
} }
@Override @Override
public BlockDivision clone(final TreeContainer parent, InputContext ic) { public BlockDivision clone(final BlockContainer parent, InputContext ic) {
return new BlockDivision(parent, this, ic); return new BlockDivision(parent, this, ic);
} }
} }

View File

@ -18,7 +18,7 @@ public class BlockExponentialNotation extends BlockPower {
* @param old * @param old
* @param ic * @param ic
*/ */
private BlockExponentialNotation(final TreeContainer parent, BlockExponentialNotation old, InputContext ic) { private BlockExponentialNotation(final BlockContainer parent, BlockExponentialNotation old, InputContext ic) {
super(parent, old, ic); super(parent, old, ic);
this.bw = old.bw; this.bw = old.bw;
this.bh = old.bh; this.bh = old.bh;
@ -41,7 +41,7 @@ public class BlockExponentialNotation extends BlockPower {
} }
@Override @Override
public BlockExponentialNotation clone(final TreeContainer parent, InputContext ic) { public BlockExponentialNotation clone(final BlockContainer parent, InputContext ic) {
return new BlockExponentialNotation(parent, this, ic); return new BlockExponentialNotation(parent, this, ic);
} }
} }

View File

@ -27,11 +27,16 @@ public class BlockLogarithm extends Block implements IParenthesis {
private int schh; private int schh;
private int nmbh; private int nmbh;
private int toph; private int toph;
private ObjectArrayList<BlockContainer> innerContainers;
public BlockLogarithm() { public BlockLogarithm() {
containerBase = new BlockContainer(this, true); containerBase = new BlockContainer(this, true);
containerNumber = new BlockContainer(this, false); containerNumber = new BlockContainer(this, false);
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(2);
innerContainers.add(containerBase);
innerContainers.add(containerNumber);
} }
public BlockLogarithm(final ObjectArrayList<Block> blocks) { public BlockLogarithm(final ObjectArrayList<Block> blocks) {
@ -40,7 +45,7 @@ public class BlockLogarithm extends Block implements IParenthesis {
recomputeDimensions(); recomputeDimensions();
} }
private BlockLogarithm(final TreeContainer parent, BlockLogarithm old, InputContext ic) { private BlockLogarithm(final BlockContainer parent, BlockLogarithm old, InputContext ic) {
super(parent, old); super(parent, old);
containerBase = old.containerBase.clone(this, ic); containerBase = old.containerBase.clone(this, ic);
containerNumber = old.containerNumber.clone(this, ic); containerNumber = old.containerNumber.clone(this, ic);
@ -80,38 +85,16 @@ public class BlockLogarithm extends Block implements IParenthesis {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerBase.appendBlock(caret, newBlock, splitAdjacent); added = added | containerBase.appendBlock(caret, newBlock);
added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); added = added | containerNumber.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
removed = removed | containerBase.deleteBlock(caret);
removed = removed | containerNumber.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
BlockReference<?> bl = null;
bl = containerBase.getBlock(caret);
if (bl != null) {
return bl;
}
bl = containerNumber.getBlock(caret);
return bl;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
if (prefix == null) { if (prefix == null) {
@ -163,11 +146,6 @@ public class BlockLogarithm extends Block implements IParenthesis {
return containerNumber; return containerNumber;
} }
@Override
public int computeCaretMaxBound() {
return containerBase.computeCaretMaxBound() + containerNumber.computeCaretMaxBound();
}
@Override @Override
public Feature toFeature(final MathContext context) throws Error { public Feature toFeature(final MathContext context) throws Error {
final Function base = getBaseContainer().toFunction(context); final Function base = getBaseContainer().toFunction(context);
@ -185,14 +163,11 @@ public class BlockLogarithm extends Block implements IParenthesis {
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public ObjectArrayList<BlockContainer> getInnerContainers() {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>(); return innerContainers;
output.add(containerBase);
output.add(containerNumber);
return output;
} }
@Override @Override
public BlockLogarithm clone(final TreeContainer parent, InputContext ic) { public BlockLogarithm clone(final BlockContainer parent, InputContext ic) {
return new BlockLogarithm(parent, this, ic); return new BlockLogarithm(parent, this, ic);
} }

View File

@ -8,12 +8,12 @@ public class BlockNumericChar extends BlockChar {
super(ch); super(ch);
} }
private BlockNumericChar(final TreeContainer parent, BlockNumericChar old, InputContext ic) { private BlockNumericChar(final BlockContainer parent, BlockNumericChar old, InputContext ic) {
super(parent, old, ic); super(parent, old, ic);
} }
@Override @Override
public BlockNumericChar clone(final TreeContainer parent, InputContext ic) { public BlockNumericChar clone(final BlockContainer parent, InputContext ic) {
return new BlockNumericChar(parent, this, ic); return new BlockNumericChar(parent, this, ic);
} }
} }

View File

@ -0,0 +1,26 @@
package it.cavallium.warppi.gui.expression.blocks;
import it.cavallium.warppi.gui.GraphicalElement;
public interface BlockOrContainer extends GraphicalElement {
BlockOrContainer getParent();
BlockOrContainer getAt(int index);
default void recomputeDimensionsToRoot() {
var parent = this;
while (parent != null) {
parent.recomputeDimensions();
parent = parent.getParent();
}
}
default BlockContainer getRootContainer() {
var parent = this;
while (parent != null) {
parent = parent.getParent();
}
return (BlockContainer) parent;
}
int getIndex();
}

View File

@ -9,13 +9,15 @@ import it.cavallium.warppi.util.Error;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class BlockParenthesis extends BlockParenthesisAbstract { public class BlockParenthesis extends BlockParenthesisAbstract {
private ObjectArrayList<BlockContainer> innerContainersCached;
public BlockParenthesis() {} public BlockParenthesis() {}
public BlockParenthesis(final ObjectArrayList<Block> blocks) { public BlockParenthesis(final ObjectArrayList<Block> blocks) {
super(blocks); super(blocks);
} }
private BlockParenthesis(final TreeContainer parent, BlockParenthesis old, InputContext ic) { private BlockParenthesis(final BlockContainer parent, BlockParenthesis old, InputContext ic) {
super(parent, old, ic); super(parent, old, ic);
} }
@ -31,14 +33,7 @@ public class BlockParenthesis extends BlockParenthesisAbstract {
} }
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public BlockParenthesis clone(final BlockContainer parent, InputContext ic) {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>();
output.add(getNumberContainer());
return output;
}
@Override
public BlockParenthesis clone(final TreeContainer parent, InputContext ic) {
return new BlockParenthesis(parent, this, ic); return new BlockParenthesis(parent, this, ic);
} }

View File

@ -14,6 +14,7 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
private final BlockContainer containerNumber; private final BlockContainer containerNumber;
private final String prefix; private final String prefix;
private final ObjectArrayList<BlockContainer> innerContainers;
private int prw; private int prw;
private int chw; private int chw;
private int chh; private int chh;
@ -23,12 +24,18 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
this.prefix = prefix; this.prefix = prefix;
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
public BlockParenthesisAbstract() { public BlockParenthesisAbstract() {
containerNumber = new BlockContainer(this, false); containerNumber = new BlockContainer(this, false);
prefix = null; prefix = null;
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
/** /**
@ -36,19 +43,25 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
* @param old * @param old
* @param ic * @param ic
*/ */
BlockParenthesisAbstract(final TreeContainer parent, BlockParenthesisAbstract old, InputContext ic) { BlockParenthesisAbstract(final BlockContainer parent, BlockParenthesisAbstract old, InputContext ic) {
super(parent, old); super(parent, old);
containerNumber = old.containerNumber.clone(this, ic); containerNumber = old.containerNumber.clone(this, ic);
prefix = old.prefix; prefix = old.prefix;
prw = old.prw; prw = old.prw;
chw = old.chw; chw = old.chw;
chh = old.chh; chh = old.chh;
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
public BlockParenthesisAbstract(final ObjectArrayList<Block> blocks) { public BlockParenthesisAbstract(final ObjectArrayList<Block> blocks) {
containerNumber = new BlockContainer(this, false, blocks); containerNumber = new BlockContainer(this, false, blocks);
prefix = null; prefix = null;
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
@Override @Override
@ -73,30 +86,15 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); added = added | containerNumber.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
removed = removed | containerNumber.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return containerNumber.getBlock(caret);
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
if (prefix == null) { if (prefix == null) {
@ -122,11 +120,6 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
return containerNumber; return containerNumber;
} }
@Override
public int computeCaretMaxBound() {
return containerNumber.computeCaretMaxBound();
}
@Override @Override
public abstract Feature toFeature(MathContext context) throws Error; public abstract Feature toFeature(MathContext context) throws Error;
@ -139,9 +132,7 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public ObjectArrayList<BlockContainer> getInnerContainers() {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>(); return innerContainers;
output.add(containerNumber);
return output;
} }
} }

View File

@ -0,0 +1,196 @@
package it.cavallium.warppi.gui.expression.blocks;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntCollections;
import org.apache.commons.lang3.NotImplementedException;
import java.util.Collections;
import java.util.Objects;
public final class BlockPosition {
private final BlockOrContainer pos;
public BlockPosition(BlockOrContainer pos) {
this.pos = pos;
}
public BlockPosition(Block block) {
this.pos = block;
}
public BlockPosition(BlockContainer container) {
this.pos = container;
}
public boolean isBlock() {
return pos instanceof Block;
}
public boolean isContainer() {
return pos instanceof BlockContainer;
}
public Block getBlock() {
return (Block) pos;
}
public BlockContainer getContainer() {
return (BlockContainer) pos;
}
public BlockOrContainer get() {
return pos;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (BlockPosition) obj;
return Objects.equals(this.pos, that.pos);
}
@Override
public int hashCode() {
return Objects.hash(pos);
}
@Override
public String toString() {
return "BlockPosition[" +
"pos=" + pos + ']';
}
public BlockPosition getNext() {
if (pos instanceof BlockContainer) {
var container = (BlockContainer) pos;
var content = container.getContent();
if (content.isEmpty()) {
BlockContainer nextContainer;
if (container.hasParent()) {
var containers = container.getParentBlock().getInnerContainers();
var it = containers.listIterator(containers.indexOf(container) + 1);
nextContainer = it.hasNext() ? it.next() : null;
} else {
nextContainer = null;
}
if (nextContainer != null) {
return new BlockPosition(nextContainer);
} else {
var parentBlock = container.getParentBlock();
return parentBlock != null ? new BlockPosition(parentBlock) : null;
}
} else {
var targetBlock = content.get(0);
var innerContainers = targetBlock.getInnerContainers();
if (innerContainers != null && !innerContainers.isEmpty()) {
return new BlockPosition(innerContainers.get(0));
} else {
return new BlockPosition(targetBlock);
}
}
} else if (pos instanceof Block) {
var block = (Block) pos;
var ref = block.getReference();
var nextBlock = ref.getNextBlock();
if (nextBlock == null) {
var container = block.getParentContainer();
BlockContainer nextContainer;
if (container.hasParent()) {
var containers = container.getParentBlock().getInnerContainers();
var it = containers.listIterator(containers.indexOf(container) + 1);
nextContainer = it.hasNext() ? it.next() : null;
} else {
nextContainer = null;
}
if (nextContainer != null) {
return new BlockPosition(nextContainer);
} else {
var parentBlock = container.getParentBlock();
return parentBlock != null ? new BlockPosition(parentBlock) : null;
}
} else {
var targetBlock = nextBlock.get();
var innerContainers = targetBlock.getInnerContainers();
if (innerContainers != null && !innerContainers.isEmpty()) {
return new BlockPosition(innerContainers.get(0));
} else {
return new BlockPosition(targetBlock);
}
}
} else {
throw new UnsupportedOperationException();
}
}
public BlockPosition getPrevious() {
if (pos instanceof BlockContainer) {
var container = (BlockContainer) pos;
if (container.hasParent()) {
var parentBlock = container.getParentBlock();
var innerContainers = parentBlock.getInnerContainers();
if (innerContainers != null) {
var it = innerContainers.listIterator(innerContainers.indexOf(container));
if (it.hasPrevious()) {
var prevContainer = it.previous();
var prevContainerLastBlock = prevContainer.getLastBlock();
if (prevContainerLastBlock != null) {
return new BlockPosition(prevContainerLastBlock);
} else {
return new BlockPosition(prevContainer);
}
} else {
var parentContainer = parentBlock.getParentContainer();
var blocks = parentContainer.getContentUnsafe();
var bIt = blocks.listIterator(blocks.indexOf(parentBlock));
if (bIt.hasPrevious()) {
return new BlockPosition(bIt.previous());
} else {
return new BlockPosition(parentContainer);
}
}
} else {
throw new UnsupportedOperationException();
}
} else {
return null;
}
} else if (pos instanceof Block) {
var block = (Block) pos;
var innerContainers = block.getInnerContainers();
if (innerContainers != null) {
var lastContainer = innerContainers.get(innerContainers.size() - 1);
var lastBlock = lastContainer.getLastBlock();
if (lastBlock != null) {
return new BlockPosition(lastBlock);
} else {
return new BlockPosition(lastContainer);
}
}
var ref = block.getReference();
var prevBlock = ref.getPreviousBlock();
if (prevBlock == null) {
var container = block.getParentContainer();
return new BlockPosition(container);
} else {
var targetBlock = prevBlock.get();
return new BlockPosition(targetBlock);
}
} else {
throw new UnsupportedOperationException();
}
}
public IntArrayList getURL() {
var url = new IntArrayList();
var parent = pos;
while (parent != null) {
var index = parent.getIndex();
if (index == -1) break;
url.add(index);
parent = parent.getParent();
}
Collections.reverse(url);
return url;
}
}

View File

@ -14,15 +14,22 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class BlockPower extends Block { public class BlockPower extends Block {
private final BlockContainer containerExponent; private final BlockContainer containerExponent;
private final ObjectArrayList<BlockContainer> innerContainers;
public BlockPower() { public BlockPower() {
containerExponent = new BlockContainer(this, true); containerExponent = new BlockContainer(this, true);
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerExponent);
} }
protected BlockPower(final TreeContainer parent, BlockPower old, InputContext ic) { protected BlockPower(final BlockContainer parent, BlockPower old, InputContext ic) {
super(parent, old); super(parent, old);
this.containerExponent = old.containerExponent.clone(this, ic); this.containerExponent = old.containerExponent.clone(this, ic);
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerExponent);
} }
@Override @Override
@ -33,29 +40,14 @@ public class BlockPower extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerExponent.appendBlock(caret, newBlock, splitAdjacent); added = added | containerExponent.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(Caret caret) {
boolean removed = false;
removed = removed | containerExponent.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return containerExponent.getBlock(caret);
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
@ -77,11 +69,6 @@ public class BlockPower extends Block {
return containerExponent; return containerExponent;
} }
@Override
public int computeCaretMaxBound() {
return containerExponent.computeCaretMaxBound();
}
@Override @Override
public Feature toFeature(final MathContext context) throws Error { public Feature toFeature(final MathContext context) throws Error {
final Function exp = getExponentContainer().toFunction(context); final Function exp = getExponentContainer().toFunction(context);
@ -95,13 +82,11 @@ public class BlockPower extends Block {
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public ObjectArrayList<BlockContainer> getInnerContainers() {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>(); return innerContainers;
output.add(containerExponent);
return output;
} }
@Override @Override
public BlockPower clone(final TreeContainer parent, InputContext ic) { public BlockPower clone(final BlockContainer parent, InputContext ic) {
return new BlockPower(parent, this, ic); return new BlockPower(parent, this, ic);
} }
} }

View File

@ -14,21 +14,23 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class BlockPower2 extends Block { public class BlockPower2 extends Block {
private final BlockContainer containerExponent; private final BlockContainer containerExponent;
private final ObjectArrayList<BlockContainer> innerContainers;
public BlockPower2() { public BlockPower2() {
containerExponent = new BlockContainer(this, true); containerExponent = new BlockContainer(this, true);
containerExponent.addBlock(0, new BlockNumericChar('2')); containerExponent.addBlock(0, new BlockNumericChar('2'));
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerExponent);
} }
private BlockPower2(final TreeContainer parent, BlockPower2 old, InputContext ic) { private BlockPower2(final BlockContainer parent, BlockPower2 old, InputContext ic) {
super(parent, old); super(parent, old);
this.containerExponent = old.containerExponent.clone(this, ic); this.containerExponent = old.containerExponent.clone(this, ic);
}
@Override innerContainers = new ObjectArrayList<>(1);
public int getCaretDeltaPositionAfterCreation() { innerContainers.add(containerExponent);
return 3;
} }
@Override @Override
@ -39,30 +41,15 @@ public class BlockPower2 extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerExponent.appendBlock(caret, newBlock, splitAdjacent); added = added | containerExponent.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
removed = removed | containerExponent.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return containerExponent.getBlock(caret);
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
final int w2 = containerExponent.getWidth(); final int w2 = containerExponent.getWidth();
@ -83,11 +70,6 @@ public class BlockPower2 extends Block {
return containerExponent; return containerExponent;
} }
@Override
public int computeCaretMaxBound() {
return containerExponent.computeCaretMaxBound();
}
@Override @Override
public Feature toFeature(final MathContext context) throws Error { public Feature toFeature(final MathContext context) throws Error {
final Function exp = getExponentContainer().toFunction(context); final Function exp = getExponentContainer().toFunction(context);
@ -101,13 +83,11 @@ public class BlockPower2 extends Block {
@Override @Override
public ObjectArrayList<BlockContainer> getInnerContainers() { public ObjectArrayList<BlockContainer> getInnerContainers() {
ObjectArrayList<BlockContainer> output = new ObjectArrayList<>(); return innerContainers;
output.add(containerExponent);
return output;
} }
@Override @Override
public BlockPower2 clone(final TreeContainer parent, InputContext ic) { public BlockPower2 clone(final BlockContainer parent, InputContext ic) {
return new BlockPower2(parent, this, ic); return new BlockPower2(parent, this, ic);
} }
} }

View File

@ -1,13 +1,17 @@
package it.cavallium.warppi.gui.expression.blocks; package it.cavallium.warppi.gui.expression.blocks;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class BlockReference<T extends Block> { public class BlockReference<T extends Block> {
private final T block; private final T block;
private final BlockContainer container; private final BlockContainer container;
private final int blockPosition; private int cachedBlockPosition;
private final ObjectArrayList<Block> containerBlocks;
public BlockReference(final T block, final int blockPosition, final BlockContainer container) { public BlockReference(final T block, final int cachedBlockPosition, final ObjectArrayList<Block> containerBlocks, final BlockContainer container) {
this.block = block; this.block = block;
this.blockPosition = blockPosition; this.cachedBlockPosition = cachedBlockPosition;
this.containerBlocks = containerBlocks;
this.container = container; this.container = container;
} }
@ -20,23 +24,28 @@ public class BlockReference<T extends Block> {
} }
public int getIndex() { public int getIndex() {
return blockPosition; if (containerBlocks.size() > cachedBlockPosition && cachedBlockPosition >= 0
&& containerBlocks.get(cachedBlockPosition) == block) {
return cachedBlockPosition;
} else {
return cachedBlockPosition = containerBlocks.indexOf(block);
}
} }
public BlockReference<?> getNextBlock() { public BlockReference<?> getNextBlock() {
return getBlockAtSafe(this.blockPosition + 1); return getBlockAtSafe(getIndex() + 1);
} }
public boolean hasNextBlock() { public boolean hasNextBlock() {
return isInsideBounds(this.blockPosition + 1); return isInsideBounds(getIndex() + 1);
} }
public BlockReference<?> getPreviousBlock() { public BlockReference<?> getPreviousBlock() {
return getBlockAtSafe(this.blockPosition - 1); return getBlockAtSafe(getIndex() - 1);
} }
public boolean hasPreviousBlock() { public boolean hasPreviousBlock() {
return isInsideBounds(this.blockPosition - 1); return isInsideBounds(getIndex() - 1);
} }
private BlockReference<?> getBlockAtSafe(final int i) { private BlockReference<?> getBlockAtSafe(final int i) {

View File

@ -13,7 +13,7 @@ public class BlockSine extends BlockParenthesisAbstract {
super("SIN"); super("SIN");
} }
private BlockSine(final TreeContainer parent, BlockSine old, InputContext ic) { private BlockSine(final BlockContainer parent, BlockSine old, InputContext ic) {
super(parent, old, ic); super(parent, old, ic);
} }
@ -24,7 +24,7 @@ public class BlockSine extends BlockParenthesisAbstract {
} }
@Override @Override
public BlockSine clone(final TreeContainer parent, InputContext ic) { public BlockSine clone(final BlockContainer parent, InputContext ic) {
return new BlockSine(parent, this, ic); return new BlockSine(parent, this, ic);
} }
} }

View File

@ -14,18 +14,23 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class BlockSquareRoot extends Block { public class BlockSquareRoot extends Block {
private final BlockContainer containerNumber; private final BlockContainer containerNumber;
private final ObjectArrayList<BlockContainer> innerContainers;
private int h1; private int h1;
public BlockSquareRoot() { public BlockSquareRoot() {
containerNumber = new BlockContainer(this, false); containerNumber = new BlockContainer(this, false);
recomputeDimensions(); recomputeDimensions();
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
private BlockSquareRoot(final TreeContainer parent, BlockSquareRoot old, InputContext ic) { private BlockSquareRoot(final BlockContainer parent, BlockSquareRoot old, InputContext ic) {
super(parent, old); super(parent, old);
this.containerNumber = old.containerNumber.clone(this, ic); this.containerNumber = old.containerNumber.clone(this, ic);
this.h1 = old.h1; this.h1 = old.h1;
innerContainers = new ObjectArrayList<>(1);
innerContainers.add(containerNumber);
} }
@Override @Override
@ -44,30 +49,15 @@ public class BlockSquareRoot extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
boolean added = false; boolean added = false;
added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); added = added | containerNumber.appendBlock(caret, newBlock);
if (added) { if (added) {
recomputeDimensions(); recomputeDimensions();
} }
return added; return added;
} }
@Override
public boolean deleteBlock(final Caret caret) {
boolean removed = false;
removed = removed | containerNumber.deleteBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return containerNumber.getBlock(caret);
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
final int w1 = containerNumber.getWidth(); final int w1 = containerNumber.getWidth();
@ -93,11 +83,6 @@ public class BlockSquareRoot extends Block {
return containerNumber; return containerNumber;
} }
@Override
public int computeCaretMaxBound() {
return containerNumber.computeCaretMaxBound();
}
@Override @Override
public Feature toFeature(final MathContext context) throws Error { public Feature toFeature(final MathContext context) throws Error {
final Function contnt = getNumberContainer().toFunction(context); final Function contnt = getNumberContainer().toFunction(context);
@ -119,7 +104,7 @@ public class BlockSquareRoot extends Block {
} }
@Override @Override
public BlockSquareRoot clone(final TreeContainer parent, InputContext ic) { public BlockSquareRoot clone(final BlockContainer parent, InputContext ic) {
return new BlockSquareRoot(parent, this, ic); return new BlockSquareRoot(parent, this, ic);
} }
} }

View File

@ -16,7 +16,7 @@ public class BlockUndefined extends Block {
recomputeDimensions(); recomputeDimensions();
} }
private BlockUndefined(final TreeContainer parent, BlockUndefined old, InputContext ic) { private BlockUndefined(final BlockContainer parent, BlockUndefined old, InputContext ic) {
super(parent, old); super(parent, old);
} }
@ -28,20 +28,10 @@ public class BlockUndefined extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
return false; return false;
} }
@Override
public boolean deleteBlock(final Caret caret) {
return false;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return null;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
width = BlockContainer.getDefaultFont(small).getStringWidth("UNDEFINED"); width = BlockContainer.getDefaultFont(small).getStringWidth("UNDEFINED");
@ -55,11 +45,6 @@ public class BlockUndefined extends Block {
recomputeDimensions(); recomputeDimensions();
} }
@Override
public int computeCaretMaxBound() {
return 0;
}
@Override @Override
public Feature toFeature(final MathContext context) { public Feature toFeature(final MathContext context) {
return new FeatureChar(MathematicalSymbols.UNDEFINED); return new FeatureChar(MathematicalSymbols.UNDEFINED);
@ -76,7 +61,7 @@ public class BlockUndefined extends Block {
} }
@Override @Override
public BlockUndefined clone(final TreeContainer parent, InputContext ic) { public BlockUndefined clone(final BlockContainer parent, InputContext ic) {
return new BlockUndefined(parent, this, ic); return new BlockUndefined(parent, this, ic);
} }

View File

@ -43,7 +43,7 @@ public class BlockVariable extends Block {
recomputeDimensions(); recomputeDimensions();
} }
private BlockVariable(final TreeContainer parent, BlockVariable old, InputContext ic) { private BlockVariable(final BlockContainer parent, BlockVariable old, InputContext ic) {
super(parent, old); super(parent, old);
this.ic = ic; this.ic = ic;
this.ch = old.ch; this.ch = old.ch;
@ -106,20 +106,10 @@ public class BlockVariable extends Block {
} }
@Override @Override
public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { public boolean appendBlock(final Caret caret, final Block newBlock) {
return false; return false;
} }
@Override
public boolean deleteBlock(final Caret caret) {
return false;
}
@Override
public BlockReference<?> getBlock(final Caret caret) {
return null;
}
@Override @Override
public void recomputeDimensions() { public void recomputeDimensions() {
width = BlockContainer.getDefaultCharWidth(small); width = BlockContainer.getDefaultCharWidth(small);
@ -137,11 +127,6 @@ public class BlockVariable extends Block {
return ch; return ch;
} }
@Override
public int computeCaretMaxBound() {
return 0;
}
@Override @Override
public ExtraMenu<?> getExtraMenu() { public ExtraMenu<?> getExtraMenu() {
return menu; return menu;
@ -271,7 +256,7 @@ public class BlockVariable extends Block {
} }
@Override @Override
public VariableMenu clone(final TreeContainer parent, InputContext ic) { public VariableMenu clone(final BlockContainer parent, InputContext ic) {
return new VariableMenu(this, block.clone(parent, ic)); return new VariableMenu(this, block.clone(parent, ic));
} }
@ -293,7 +278,7 @@ public class BlockVariable extends Block {
} }
@Override @Override
public BlockVariable clone(final TreeContainer parent, InputContext ic) { public BlockVariable clone(final BlockContainer parent, InputContext ic) {
return new BlockVariable(parent, this, ic); return new BlockVariable(parent, this, ic);
} }
} }

View File

@ -7,10 +7,7 @@ import it.cavallium.warppi.gui.expression.Caret;
import it.cavallium.warppi.gui.expression.CaretState; import it.cavallium.warppi.gui.expression.CaretState;
import it.cavallium.warppi.gui.expression.ExtraMenu; import it.cavallium.warppi.gui.expression.ExtraMenu;
import it.cavallium.warppi.gui.expression.InputContext; import it.cavallium.warppi.gui.expression.InputContext;
import it.cavallium.warppi.gui.expression.blocks.Block; import it.cavallium.warppi.gui.expression.blocks.*;
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.expression.layouts.InputLayout;
import it.cavallium.warppi.gui.graphicengine.Renderer; import it.cavallium.warppi.gui.graphicengine.Renderer;
import it.cavallium.warppi.math.Function; import it.cavallium.warppi.math.Function;
@ -23,7 +20,6 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
protected Caret caret; protected Caret caret;
private static final float CARET_DURATION = 0.5f; private static final float CARET_DURATION = 0.5f;
private float caretTime; private float caretTime;
private int maxPosition = 0;
private boolean parsed = false; private boolean parsed = false;
private ExtraMenu<?> extra; private ExtraMenu<?> extra;
protected InputContext inputContext; protected InputContext inputContext;
@ -50,8 +46,8 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
public InputContainer(final InputContext ic, final boolean small, final int minWidth, final int minHeight) { public InputContainer(final InputContext ic, final boolean small, final int minWidth, final int minHeight) {
inputContext = ic; inputContext = ic;
caret = new Caret(CaretState.VISIBLE_ON, 0);
root = new BlockContainer(null, small, false); root = new BlockContainer(null, small, false);
caret = new Caret(CaretState.VISIBLE_ON, new BlockPosition(root));
} }
/** /**
@ -62,10 +58,9 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
protected InputContainer(InputContainer old, InputContext ic) { protected InputContainer(InputContainer old, InputContext ic) {
this.caretTime = old.caretTime; this.caretTime = old.caretTime;
this.extra = old.extra == null ? null : old.extra.clone(null, ic); 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.inputContext = ic;
this.root = old.root == null ? null : old.root.clone(null, 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; this.parsed = old.parsed;
} }
@ -76,14 +71,9 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
public void typeBlock(final Block b) { public void typeBlock(final Block b) {
if (b != null) { if (b != null) {
caret.resetRemaining(); if (root.appendBlock(caret, b)) {
var innerPos = b.getFirstInnerPosition();
// todo: allow blocks to dinamically choose insert mode caret.setPosition(innerPos == null ? new BlockPosition(b) : innerPos);
var splitAdjacent = b instanceof BlockDivision;
if (root.appendBlock(caret, b, splitAdjacent)) {
caret.setPosition(caret.getPosition() + b.getCaretDeltaPositionAfterCreation());
maxPosition = root.computeCaretMaxBound();
root.recomputeDimensions(); root.recomputeDimensions();
} }
closeExtra(); closeExtra();
@ -97,13 +87,71 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
} }
public void del() { public void del() {
caret.resetRemaining(); var pos = caret.getPos();
if (root.deleteBlock(caret)) { BlockOrContainer currentElementToRecompute;
root.recomputeDimensions(); 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 lastBlock = prevContainer.getLastBlock();
if (lastBlock != null) {
caret.setPosition(new BlockPosition(lastBlock));
currentElementToRecompute = null;
removed = false;
} else {
caret.setPosition(new BlockPosition(prevContainer));
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 (caret.getPosition() > 0) { if (removed) {
caret.setPosition(caret.getPosition() - 1); while (currentElementToRecompute != null) {
maxPosition = root.computeCaretMaxBound(); currentElementToRecompute.recomputeDimensions();
currentElementToRecompute = currentElementToRecompute.getParent();
}
} }
caret.turnOn(); caret.turnOn();
caretTime = 0; caretTime = 0;
@ -111,46 +159,25 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
} }
public BlockReference<?> getSelectedBlock() { public BlockReference<?> getSelectedBlock() {
caret.resetRemaining(); var pos = caret.getPos();
final BlockReference<?> selectedBlock = root.getBlock(caret); if (pos.isBlock()) {
return selectedBlock; return pos.getBlock().getReference();
} } else {
var container = pos.getContainer();
public BlockReference<?> getBlockAtCaretPosition(final int i) { if (container.hasParent()) {
final BlockReference<?> selectedBlock = root.getBlock(new Caret(CaretState.HIDDEN, i)); return container.getParentBlock().getReference();
return selectedBlock; } else {
return null;
}
}
} }
public void moveLeft() { public void moveLeft() {
final int curPos = caret.getPosition(); var prev = caret.getPos().getPrevious();
if (curPos > 0) { if (prev != null) {
caret.setPosition(curPos - 1); caret.setPosition(prev);
} else { } else {
caret.setPosition(maxPosition - 1); caret.setPosition(new BlockPosition(root.getLastBlock()));
}
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(); caret.turnOn();
caretTime = 0; caretTime = 0;
@ -158,7 +185,22 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
} }
public void moveRight() { public void moveRight() {
moveRight(1); 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 @Override
@ -217,7 +259,6 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
* Position relative to the window. * Position relative to the window.
*/ */
public void draw(final DisplayOutputDevice ge, final Renderer r, final int x, final int y) { public void draw(final DisplayOutputDevice ge, final Renderer r, final int x, final int y) {
caret.resetRemaining();
root.draw(ge, r, x, y, caret); root.draw(ge, r, x, y, caret);
if (extra != null) { if (extra != null) {
extra.draw(ge, r, caret); extra.draw(ge, r, caret);
@ -225,27 +266,13 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
} }
public void clear() { public void clear() {
caret = new Caret(CaretState.VISIBLE_ON, 0); caret = new Caret(CaretState.VISIBLE_ON, new BlockPosition(root));
root.clear(); root.clear();
maxPosition = root.computeCaretMaxBound();
recomputeDimensions(); recomputeDimensions();
} }
public boolean isEmpty() { public boolean isEmpty() {
return maxPosition <= 1; return root.getSize() == 0;
}
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) { public void setParsed(final boolean parsed) {

View File

@ -6,6 +6,9 @@ import it.cavallium.warppi.gui.expression.InputContext;
import it.cavallium.warppi.gui.expression.blocks.*; import it.cavallium.warppi.gui.expression.blocks.*;
import it.cavallium.warppi.math.MathematicalSymbols; import it.cavallium.warppi.math.MathematicalSymbols;
import java.util.ArrayList;
import java.util.List;
public class NormalInputContainer extends InputContainer { public class NormalInputContainer extends InputContainer {
@Deprecated() @Deprecated()
@ -30,7 +33,6 @@ public class NormalInputContainer extends InputContainer {
/** /**
* Copy * Copy
* @param userInput
* @param ic * @param ic
*/ */
public NormalInputContainer(InputContainer old, InputContext ic) { public NormalInputContainer(InputContainer old, InputContext ic) {
@ -93,36 +95,24 @@ public class NormalInputContainer extends InputContainer {
switch (c) { switch (c) {
case MathematicalSymbols.PARENTHESIS_CLOSE: { case MathematicalSymbols.PARENTHESIS_CLOSE: {
final BlockReference<?> ref = getSelectedBlock(); final BlockReference<?> ref = getSelectedBlock();
if (ref == null) { BlockParenthesisAbstract parenthesis = findParenthesis(ref.get());
if (parenthesis == null) {
break; break;
} else { } else {
final Caret newCaret = new Caret(CaretState.HIDDEN, caret.getPosition()); moveTo(new BlockPosition(parenthesis));
BlockContainer currentContainer;
BlockReference<?> newRef = ref;
int safeExit = 0;
do {
currentContainer = (BlockContainer) newRef.get().getParentContainer();
final int initialRelativeIndex = currentContainer.getContent().indexOf(newRef.get());
final int newIndex = newCaret.getPosition() + currentContainer.getContent().size() - initialRelativeIndex;
newRef = getBlockAtCaretPosition(newIndex);
newCaret.setPosition(newIndex);
safeExit++;
} while (newRef != null && newRef.get() instanceof IParenthesis == false && currentContainer != null && safeExit < 100000);
if (safeExit >= 100000) {
System.err.println("Error 0x001030: Infinite loop");
}
if (newRef != null) {
moveTo(newCaret.getPosition());
}
} }
break; break;
} }
case MathematicalSymbols.POWER_OF_TWO:
moveTo(new BlockPosition(getSelectedBlock().get()));
break;
case MathematicalSymbols.DIVISION: { case MathematicalSymbols.DIVISION: {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final BlockReference<BlockDivision> ref = (BlockReference<BlockDivision>) getSelectedBlock(); final BlockReference<BlockDivision> ref = (BlockReference<BlockDivision>) getSelectedBlock();
@SuppressWarnings("unused") @SuppressWarnings("unused")
final BlockContainer parentContainer = ref.getContainer(); final BlockContainer parentContainer = ref.getContainer();
BlockReference<?> currentBlock = ref; BlockReference<?> currentBlock = ref;
List<Block> blocksToMove = new ArrayList<>();
boolean groupedBefore = false; boolean groupedBefore = false;
int before = 0; int before = 0;
while (true) { while (true) {
@ -135,28 +125,39 @@ public class NormalInputContainer extends InputContainer {
if (!groupedBefore) { if (!groupedBefore) {
groupedBefore = true; groupedBefore = true;
} }
blocksToMove.add(b);
before++; before++;
} else { } else {
break; break;
} }
} }
if (groupedBefore) { if (groupedBefore) {
moveLeft(); var div = ref.get();
for (int i = 0; i < before; i++) { var upperContainer = div.getUpperContainer();
final BlockReference<?> b = getSelectedBlock(); for (int i = blocksToMove.size() - 1; i >= 0; i--) {
del(); var b = blocksToMove.get(i);
moveRight(); b.getParentContainer().removeBlockUnsafe(b);
typeBlock(b.get()); upperContainer.appendBlock(b);
moveLeft();
moveLeft();
} }
for (int i = 0; i < before + 1; i++) { div.recomputeDimensionsToRoot();
moveRight(); moveTo(new BlockPosition(div.getLowerContainer()));
}
moveRight();// Move to the divisor
} }
break; break;
} }
} }
} }
private BlockParenthesisAbstract findParenthesis(Block o) {
while (!(o instanceof BlockParenthesisAbstract)) {
var pc = o.getParentContainer();
if (!pc.hasParent()) {
return null;
}
o = pc.getParentBlock();
if (o == null) {
return null;
}
}
return (BlockParenthesisAbstract) o;
}
} }

View File

@ -6,6 +6,7 @@ import it.cavallium.warppi.gui.expression.Caret;
import it.cavallium.warppi.gui.expression.CaretState; import it.cavallium.warppi.gui.expression.CaretState;
import it.cavallium.warppi.gui.expression.blocks.Block; import it.cavallium.warppi.gui.expression.blocks.Block;
import it.cavallium.warppi.gui.expression.blocks.BlockContainer; import it.cavallium.warppi.gui.expression.blocks.BlockContainer;
import it.cavallium.warppi.gui.expression.blocks.BlockPosition;
import it.cavallium.warppi.gui.expression.layouts.OutputLayout; import it.cavallium.warppi.gui.expression.layouts.OutputLayout;
import it.cavallium.warppi.gui.graphicengine.Renderer; import it.cavallium.warppi.gui.graphicengine.Renderer;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@ -13,21 +14,27 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class OutputContainer implements GraphicalElement, OutputLayout { public abstract class OutputContainer implements GraphicalElement, OutputLayout {
private static final long serialVersionUID = -5714825964892683571L; private static final long serialVersionUID = -5714825964892683571L;
public final ObjectArrayList<BlockContainer> roots; public final ObjectArrayList<BlockContainer> roots;
private final Caret caret = new Caret(CaretState.HIDDEN, 0); private final Caret caret;
public OutputContainer() { public OutputContainer() {
roots = new ObjectArrayList<>(); roots = new ObjectArrayList<>();
roots.add(new BlockContainer()); var root = new BlockContainer();
roots.add(root);
caret = new Caret(CaretState.HIDDEN, new BlockPosition(root));
} }
public OutputContainer(final boolean small) { public OutputContainer(final boolean small) {
roots = new ObjectArrayList<>(); roots = new ObjectArrayList<>();
roots.add(new BlockContainer(null, small)); var root = new BlockContainer(null, small);
roots.add(root);
caret = new Caret(CaretState.HIDDEN, new BlockPosition(root));
} }
public OutputContainer(final boolean small, final int minWidth, final int minHeight) { public OutputContainer(final boolean small, final int minWidth, final int minHeight) {
roots = new ObjectArrayList<>(); roots = new ObjectArrayList<>();
roots.add(new BlockContainer(null, small)); var root = new BlockContainer(null, small);
roots.add(root);
caret = new Caret(CaretState.HIDDEN, new BlockPosition(root));
} }
public void setContentAsSingleGroup(final ObjectArrayList<Block> blocks) { public void setContentAsSingleGroup(final ObjectArrayList<Block> blocks) {