From 7ae4315837db6bde582a9c393f81f77491be0b15 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Wed, 23 Aug 2023 16:47:55 +0200 Subject: [PATCH] Refactor caret positioning --- core/pom.xml | 8 +- .../warppi/gui/expression/Caret.java | 47 +++-- .../warppi/gui/expression/ExtraMenu.java | 3 +- .../warppi/gui/expression/blocks/Block.java | 73 +++++-- .../gui/expression/blocks/BlockChar.java | 21 +- .../gui/expression/blocks/BlockContainer.java | 152 +++++--------- .../gui/expression/blocks/BlockDivision.java | 51 ++--- .../blocks/BlockExponentialNotation.java | 4 +- .../gui/expression/blocks/BlockLogarithm.java | 47 +---- .../expression/blocks/BlockNumericChar.java | 4 +- .../expression/blocks/BlockOrContainer.java | 26 +++ .../expression/blocks/BlockParenthesis.java | 13 +- .../blocks/BlockParenthesisAbstract.java | 43 ++-- .../gui/expression/blocks/BlockPosition.java | 196 ++++++++++++++++++ .../gui/expression/blocks/BlockPower.java | 39 ++-- .../gui/expression/blocks/BlockPower2.java | 42 +--- .../gui/expression/blocks/BlockReference.java | 25 ++- .../gui/expression/blocks/BlockSine.java | 4 +- .../expression/blocks/BlockSquareRoot.java | 33 +-- .../gui/expression/blocks/BlockUndefined.java | 21 +- .../gui/expression/blocks/BlockVariable.java | 23 +- .../expression/containers/InputContainer.java | 179 +++++++++------- .../containers/NormalInputContainer.java | 65 +++--- .../containers/OutputContainer.java | 15 +- 24 files changed, 622 insertions(+), 512 deletions(-) create mode 100644 core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockOrContainer.java create mode 100644 core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPosition.java diff --git a/core/pom.xml b/core/pom.xml index 9a010a46..d6538d01 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,13 @@ flow-nbt 1.0.1-SNAPSHOT - + + org.jetbrains + annotations + RELEASE + compile + + diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/Caret.java b/core/src/main/java/it/cavallium/warppi/gui/expression/Caret.java index 1623884f..55a6f14c 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/Caret.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/Caret.java @@ -1,23 +1,28 @@ 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; public class Caret { - private int pos; - private int remaining; + @NotNull + private BlockPosition pos; private CaretState state; private final int[] lastSize; 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 }); } - 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.pos = pos; - remaining = pos; this.lastLocation = lastLocation; this.lastSize = lastSize; } @@ -26,26 +31,27 @@ public class Caret { * Copy * @param old */ - public Caret(Caret old) { - this.pos = old.pos; - this.remaining = old.remaining; + public Caret(Caret old, BlockContainer newRoot) { + this.pos = clonePosition(old.pos, newRoot); this.state = old.state; this.lastSize = Arrays.copyOf(old.lastSize, old.lastSize.length); this.lastLocation = Arrays.copyOf(old.lastLocation, old.lastLocation.length); } - public void skip(final int i) { - remaining -= i; + private BlockPosition clonePosition(BlockPosition pos, BlockContainer newRoot) { + 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; } - public int getRemaining() { - return remaining; - } - public CaretState getState() { return state; } @@ -64,12 +70,8 @@ public class Caret { } } - public void setPosition(final int i) { - pos = i; - } - - public void resetRemaining() { - remaining = pos; + public void setPosition(final BlockPosition pos) { + this.pos = pos; } public void setLastLocation(final int x, final int y) { @@ -90,4 +92,7 @@ public class Caret { return new int[] { lastSize[0], lastSize[1] }; } + public boolean isHere(BlockOrContainer pos) { + return getPos().get() == pos; + } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java b/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java index 6fb229d6..042609be 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java @@ -5,6 +5,7 @@ import java.util.Arrays; import it.cavallium.warppi.device.display.DisplayOutputDevice; import it.cavallium.warppi.event.KeyboardEventListener; 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.TreeContainer; import it.cavallium.warppi.gui.graphicengine.Renderer; @@ -46,7 +47,7 @@ public abstract class ExtraMenu implements KeyboardEventListene return false; } - public abstract ExtraMenu clone(final TreeContainer parent, InputContext ic); + public abstract ExtraMenu clone(final BlockContainer parent, InputContext ic); public abstract ExtraMenu clone(T newBlockVariable); diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java index a754f403..ace35789 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java @@ -11,13 +11,13 @@ import it.cavallium.warppi.math.parser.features.interfaces.Feature; import it.cavallium.warppi.util.Error; 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 int width; protected int height; protected int line; - protected TreeContainer parent; + protected BlockContainer parent; public Block() { @@ -27,7 +27,7 @@ public abstract class Block implements TreeBlock, GraphicalElement { * Copy * @param b */ - public Block(TreeContainer parent, Block b) { + public Block(BlockContainer parent, Block b) { this.small = b.small; this.width = b.width; this.height = b.height; @@ -43,15 +43,10 @@ public abstract class Block implements TreeBlock, GraphicalElement { * Position relative to the window. * @param y * Position relative to the window. - * @param small */ 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 deleteBlock(Caret caret); - - public abstract BlockReference getBlock(Caret caret); + public abstract boolean appendBlock(Caret caret, Block newBlock); /** * Used only to get inner blocks when deleting the parent block. @@ -64,8 +59,6 @@ public abstract class Block implements TreeBlock, GraphicalElement { @Override public abstract void recomputeDimensions(); - public abstract int computeCaretMaxBound(); - @Override public int getWidth() { return width; @@ -81,10 +74,6 @@ public abstract class Block implements TreeBlock, GraphicalElement { return line; } - public int getCaretDeltaPositionAfterCreation() { - return 1; - } - public boolean isSmall() { return small; } @@ -98,18 +87,66 @@ public abstract class Block implements TreeBlock, GraphicalElement { public abstract Feature toFeature(MathContext context) throws Error; @Override - public TreeContainer getParentContainer() { + public BlockContainer getParentContainer() { 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 public boolean hasParent() { return parent != null; } - public void setParent(final TreeContainer parent) { + public void setParent(final BlockContainer 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; + } + } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java index d5b096d1..1a99ea3f 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java @@ -23,7 +23,7 @@ public class BlockChar extends Block { * @param b * @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); this.ch = b.ch; } @@ -36,20 +36,10 @@ public class BlockChar extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { return false; } - @Override - public boolean deleteBlock(final Caret caret) { - return false; - } - - @Override - public BlockReference getBlock(final Caret caret) { - return null; - } - @Override public void recomputeDimensions() { width = BlockContainer.getDefaultCharWidth(small) - 1; @@ -67,11 +57,6 @@ public class BlockChar extends Block { return ch; } - @Override - public int computeCaretMaxBound() { - return 0; - } - @Override public Feature toFeature(final MathContext context) { return new FeatureChar(getChar()); @@ -88,7 +73,7 @@ public class BlockChar extends Block { } @Override - public BlockChar clone(final TreeContainer parent, InputContext ic) { + public BlockChar clone(final BlockContainer parent, InputContext ic) { return new BlockChar(parent, this, ic); } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java index c496f36b..510eb3b9 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java @@ -15,9 +15,8 @@ import it.cavallium.warppi.math.parser.features.interfaces.Feature; import it.cavallium.warppi.util.Error; import it.cavallium.warppi.util.Errors; 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; @@ -30,39 +29,39 @@ public class BlockContainer implements TreeContainer, GraphicalElement { private int line; public final boolean withBorder; private boolean autoMinimums; - private final TreeBlock parent; + private final Block parent; public BlockContainer() { this(null, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true); autoMinimums = true; } - public BlockContainer(final TreeBlock parent) { + public BlockContainer(final Block parent) { this(parent, false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), 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); autoMinimums = true; } - public BlockContainer(final TreeBlock parent, final boolean small, final ObjectArrayList content) { + public BlockContainer(final Block parent, final boolean small, final ObjectArrayList content) { this(parent, small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), content, 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); 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); autoMinimums = false; } - public BlockContainer(final TreeBlock parent, final boolean small, final int minWidth, final int minHeight, final ObjectArrayList content, final boolean withBorder) { + public BlockContainer(final Block parent, final boolean small, final int minWidth, final int minHeight, final ObjectArrayList content, final boolean withBorder) { this.parent = parent; this.small = small; this.minWidth = minWidth; @@ -77,7 +76,7 @@ public class BlockContainer implements TreeContainer, GraphicalElement { recomputeDimensions(); } - private BlockContainer(final TreeBlock parent, BlockContainer old, InputContext ic) { + private BlockContainer(final Block parent, BlockContainer old, InputContext ic) { this.autoMinimums = old.autoMinimums; this.content = new ObjectArrayList<>(); for (Block b : old.content) { @@ -94,15 +93,30 @@ public class BlockContainer implements TreeContainer, GraphicalElement { 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); } @Override - public TreeBlock getParentBlock() { + public Block getParentBlock() { 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 public boolean hasParent() { return parent != null; @@ -155,7 +169,7 @@ public class BlockContainer implements TreeContainer, GraphicalElement { public BlockReference getBlockAt(final int i) { final Block b = content.get(i); - return new BlockReference<>(b, i, this); + return new BlockReference<>(b, i, content, this); } 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) { int paddingX = 1; - if (caret.getRemaining() == 0) { + if (caret.isHere(this)) { if (content.size() > 0) { BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height); } 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); } else { for (final Block b : content) { - caret.skip(1); b.draw(ge, r, x + paddingX, y + line - b.line, caret); 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); } 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; - if (caret.getRemaining() == 0) { + if (caret.isHere(this)) { addBlock(0, newBlock); added = true; } int pos = 0; for (final Block b : content) { - caret.skip(1); pos++; - added = added | b.appendBlock(caret, newBlock, splitAdjacent); - if (caret.getRemaining() == 0) { + added = added | b.appendBlock(caret, newBlock); + if (caret.isHere(b)) { addBlock(pos, newBlock); added = true; } } - caret.skip(1); if (added) { recomputeDimensions(); } 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 blocks = this.getBlockAt(pos - 1).get().getInnerBlocks(); - ObjectArrayList 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 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 public void recomputeDimensions() { 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 { final ObjectArrayList blocks = getContent(); final ObjectArrayList blockFeatures = new ObjectArrayList<>(); @@ -454,4 +386,22 @@ public class BlockContainer implements TreeContainer, GraphicalElement { return result; } + public BlockReference getReference(T block) { + var i = content.indexOf(block); + if (i < 0) return null; + return new BlockReference<>(block, i, content, this); + } + + public ObjectArrayList 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); + } } \ No newline at end of file diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java index 1942a620..cc80a692 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java @@ -19,14 +19,19 @@ public class BlockDivision extends Block { private int paddingLeftUpper; private int paddingLeftLower; private int h1; + private ObjectArrayList innerContainers; public BlockDivision() { containerUp = new BlockContainer(this, false); containerDown = new BlockContainer(this, false); 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); containerUp = old.containerUp.clone(this, ic); containerDown = old.containerDown.clone(this, ic); @@ -34,6 +39,10 @@ public class BlockDivision extends Block { paddingLeftUpper = old.paddingLeftUpper; h1 = old.h1; System.out.println(String.join(",", ""+h1, ""+old.h1, ""+line, ""+old.line)); + + innerContainers = new ObjectArrayList<>(2); + innerContainers.add(containerUp); + innerContainers.add(containerDown); } @Override @@ -47,38 +56,16 @@ public class BlockDivision extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerUp.appendBlock(caret, newBlock, splitAdjacent); - added = added | containerDown.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerUp.appendBlock(caret, newBlock); + added = added | containerDown.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { final int w1 = containerUp.getWidth(); @@ -119,11 +106,6 @@ public class BlockDivision extends Block { return containerDown; } - @Override - public int computeCaretMaxBound() { - return containerUp.computeCaretMaxBound() + containerDown.computeCaretMaxBound(); - } - @Override public Feature toFeature(final MathContext context) throws Error { final Function upper = getUpperContainer().toFunction(context); @@ -140,14 +122,11 @@ public class BlockDivision extends Block { @Override public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(containerUp); - output.add(containerDown); - return output; + return innerContainers; } @Override - public BlockDivision clone(final TreeContainer parent, InputContext ic) { + public BlockDivision clone(final BlockContainer parent, InputContext ic) { return new BlockDivision(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java index 0d2d4d87..4a86d1ba 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java @@ -18,7 +18,7 @@ public class BlockExponentialNotation extends BlockPower { * @param old * @param ic */ - private BlockExponentialNotation(final TreeContainer parent, BlockExponentialNotation old, InputContext ic) { + private BlockExponentialNotation(final BlockContainer parent, BlockExponentialNotation old, InputContext ic) { super(parent, old, ic); this.bw = old.bw; this.bh = old.bh; @@ -41,7 +41,7 @@ public class BlockExponentialNotation extends BlockPower { } @Override - public BlockExponentialNotation clone(final TreeContainer parent, InputContext ic) { + public BlockExponentialNotation clone(final BlockContainer parent, InputContext ic) { return new BlockExponentialNotation(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java index 9c68ce61..b1016fd1 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java @@ -27,11 +27,16 @@ public class BlockLogarithm extends Block implements IParenthesis { private int schh; private int nmbh; private int toph; + private ObjectArrayList innerContainers; public BlockLogarithm() { containerBase = new BlockContainer(this, true); containerNumber = new BlockContainer(this, false); recomputeDimensions(); + + innerContainers = new ObjectArrayList<>(2); + innerContainers.add(containerBase); + innerContainers.add(containerNumber); } public BlockLogarithm(final ObjectArrayList blocks) { @@ -40,7 +45,7 @@ public class BlockLogarithm extends Block implements IParenthesis { recomputeDimensions(); } - private BlockLogarithm(final TreeContainer parent, BlockLogarithm old, InputContext ic) { + private BlockLogarithm(final BlockContainer parent, BlockLogarithm old, InputContext ic) { super(parent, old); containerBase = old.containerBase.clone(this, ic); containerNumber = old.containerNumber.clone(this, ic); @@ -80,38 +85,16 @@ public class BlockLogarithm extends Block implements IParenthesis { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerBase.appendBlock(caret, newBlock, splitAdjacent); - added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerBase.appendBlock(caret, newBlock); + added = added | containerNumber.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { if (prefix == null) { @@ -163,11 +146,6 @@ public class BlockLogarithm extends Block implements IParenthesis { return containerNumber; } - @Override - public int computeCaretMaxBound() { - return containerBase.computeCaretMaxBound() + containerNumber.computeCaretMaxBound(); - } - @Override public Feature toFeature(final MathContext context) throws Error { final Function base = getBaseContainer().toFunction(context); @@ -185,14 +163,11 @@ public class BlockLogarithm extends Block implements IParenthesis { @Override public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(containerBase); - output.add(containerNumber); - return output; + return innerContainers; } @Override - public BlockLogarithm clone(final TreeContainer parent, InputContext ic) { + public BlockLogarithm clone(final BlockContainer parent, InputContext ic) { return new BlockLogarithm(parent, this, ic); } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java index ed44c709..ec7a26a6 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java @@ -8,12 +8,12 @@ public class BlockNumericChar extends BlockChar { super(ch); } - private BlockNumericChar(final TreeContainer parent, BlockNumericChar old, InputContext ic) { + private BlockNumericChar(final BlockContainer parent, BlockNumericChar old, InputContext ic) { super(parent, old, ic); } @Override - public BlockNumericChar clone(final TreeContainer parent, InputContext ic) { + public BlockNumericChar clone(final BlockContainer parent, InputContext ic) { return new BlockNumericChar(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockOrContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockOrContainer.java new file mode 100644 index 00000000..10b06398 --- /dev/null +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockOrContainer.java @@ -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(); +} diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java index e4cfd2cf..cfce6f4f 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java @@ -9,13 +9,15 @@ import it.cavallium.warppi.util.Error; import it.unimi.dsi.fastutil.objects.ObjectArrayList; public class BlockParenthesis extends BlockParenthesisAbstract { + private ObjectArrayList innerContainersCached; + public BlockParenthesis() {} public BlockParenthesis(final ObjectArrayList 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); } @@ -31,14 +33,7 @@ public class BlockParenthesis extends BlockParenthesisAbstract { } @Override - public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(getNumberContainer()); - return output; - } - - @Override - public BlockParenthesis clone(final TreeContainer parent, InputContext ic) { + public BlockParenthesis clone(final BlockContainer parent, InputContext ic) { return new BlockParenthesis(parent, this, ic); } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java index 2c99d953..eba3bda8 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java @@ -14,6 +14,7 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth private final BlockContainer containerNumber; private final String prefix; + private final ObjectArrayList innerContainers; private int prw; private int chw; private int chh; @@ -23,12 +24,18 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth this.prefix = prefix; recomputeDimensions(); + + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerNumber); } public BlockParenthesisAbstract() { containerNumber = new BlockContainer(this, false); prefix = null; recomputeDimensions(); + + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerNumber); } /** @@ -36,19 +43,25 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth * @param old * @param ic */ - BlockParenthesisAbstract(final TreeContainer parent, BlockParenthesisAbstract old, InputContext ic) { + BlockParenthesisAbstract(final BlockContainer parent, BlockParenthesisAbstract old, InputContext ic) { super(parent, old); containerNumber = old.containerNumber.clone(this, ic); prefix = old.prefix; prw = old.prw; chw = old.chw; chh = old.chh; + + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerNumber); } public BlockParenthesisAbstract(final ObjectArrayList blocks) { containerNumber = new BlockContainer(this, false, blocks); prefix = null; recomputeDimensions(); + + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerNumber); } @Override @@ -73,30 +86,15 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerNumber.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { if (prefix == null) { @@ -122,11 +120,6 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth return containerNumber; } - @Override - public int computeCaretMaxBound() { - return containerNumber.computeCaretMaxBound(); - } - @Override public abstract Feature toFeature(MathContext context) throws Error; @@ -139,9 +132,7 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth @Override public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(containerNumber); - return output; + return innerContainers; } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPosition.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPosition.java new file mode 100644 index 00000000..e51cf455 --- /dev/null +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPosition.java @@ -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; + } +} diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java index 408003c2..0cefca06 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java @@ -14,15 +14,22 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; public class BlockPower extends Block { private final BlockContainer containerExponent; + private final ObjectArrayList innerContainers; public BlockPower() { containerExponent = new BlockContainer(this, true); 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); this.containerExponent = old.containerExponent.clone(this, ic); + + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerExponent); } @Override @@ -33,29 +40,14 @@ public class BlockPower extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerExponent.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerExponent.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { @@ -77,11 +69,6 @@ public class BlockPower extends Block { return containerExponent; } - @Override - public int computeCaretMaxBound() { - return containerExponent.computeCaretMaxBound(); - } - @Override public Feature toFeature(final MathContext context) throws Error { final Function exp = getExponentContainer().toFunction(context); @@ -95,13 +82,11 @@ public class BlockPower extends Block { @Override public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(containerExponent); - return output; + return innerContainers; } @Override - public BlockPower clone(final TreeContainer parent, InputContext ic) { + public BlockPower clone(final BlockContainer parent, InputContext ic) { return new BlockPower(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java index da282657..a00b718e 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java @@ -14,21 +14,23 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; public class BlockPower2 extends Block { private final BlockContainer containerExponent; + private final ObjectArrayList innerContainers; public BlockPower2() { containerExponent = new BlockContainer(this, true); containerExponent.addBlock(0, new BlockNumericChar('2')); 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); this.containerExponent = old.containerExponent.clone(this, ic); - } - @Override - public int getCaretDeltaPositionAfterCreation() { - return 3; + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerExponent); } @Override @@ -39,30 +41,15 @@ public class BlockPower2 extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerExponent.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerExponent.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { final int w2 = containerExponent.getWidth(); @@ -83,11 +70,6 @@ public class BlockPower2 extends Block { return containerExponent; } - @Override - public int computeCaretMaxBound() { - return containerExponent.computeCaretMaxBound(); - } - @Override public Feature toFeature(final MathContext context) throws Error { final Function exp = getExponentContainer().toFunction(context); @@ -101,13 +83,11 @@ public class BlockPower2 extends Block { @Override public ObjectArrayList getInnerContainers() { - ObjectArrayList output = new ObjectArrayList<>(); - output.add(containerExponent); - return output; + return innerContainers; } @Override - public BlockPower2 clone(final TreeContainer parent, InputContext ic) { + public BlockPower2 clone(final BlockContainer parent, InputContext ic) { return new BlockPower2(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockReference.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockReference.java index 4099ff6a..e5da70fe 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockReference.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockReference.java @@ -1,13 +1,17 @@ package it.cavallium.warppi.gui.expression.blocks; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + public class BlockReference { private final T block; private final BlockContainer container; - private final int blockPosition; + private int cachedBlockPosition; + private final ObjectArrayList containerBlocks; - public BlockReference(final T block, final int blockPosition, final BlockContainer container) { + public BlockReference(final T block, final int cachedBlockPosition, final ObjectArrayList containerBlocks, final BlockContainer container) { this.block = block; - this.blockPosition = blockPosition; + this.cachedBlockPosition = cachedBlockPosition; + this.containerBlocks = containerBlocks; this.container = container; } @@ -20,23 +24,28 @@ public class BlockReference { } 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() { - return getBlockAtSafe(this.blockPosition + 1); + return getBlockAtSafe(getIndex() + 1); } public boolean hasNextBlock() { - return isInsideBounds(this.blockPosition + 1); + return isInsideBounds(getIndex() + 1); } public BlockReference getPreviousBlock() { - return getBlockAtSafe(this.blockPosition - 1); + return getBlockAtSafe(getIndex() - 1); } public boolean hasPreviousBlock() { - return isInsideBounds(this.blockPosition - 1); + return isInsideBounds(getIndex() - 1); } private BlockReference getBlockAtSafe(final int i) { diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java index 08998ba9..69eed389 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java @@ -13,7 +13,7 @@ public class BlockSine extends BlockParenthesisAbstract { super("SIN"); } - private BlockSine(final TreeContainer parent, BlockSine old, InputContext ic) { + private BlockSine(final BlockContainer parent, BlockSine old, InputContext ic) { super(parent, old, ic); } @@ -24,7 +24,7 @@ public class BlockSine extends BlockParenthesisAbstract { } @Override - public BlockSine clone(final TreeContainer parent, InputContext ic) { + public BlockSine clone(final BlockContainer parent, InputContext ic) { return new BlockSine(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java index a9c1ed03..56c476d2 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java @@ -14,18 +14,23 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; public class BlockSquareRoot extends Block { private final BlockContainer containerNumber; + private final ObjectArrayList innerContainers; private int h1; public BlockSquareRoot() { containerNumber = new BlockContainer(this, false); 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); this.containerNumber = old.containerNumber.clone(this, ic); this.h1 = old.h1; + innerContainers = new ObjectArrayList<>(1); + innerContainers.add(containerNumber); } @Override @@ -44,30 +49,15 @@ public class BlockSquareRoot extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { boolean added = false; - added = added | containerNumber.appendBlock(caret, newBlock, splitAdjacent); + added = added | containerNumber.appendBlock(caret, newBlock); if (added) { recomputeDimensions(); } 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 public void recomputeDimensions() { final int w1 = containerNumber.getWidth(); @@ -93,11 +83,6 @@ public class BlockSquareRoot extends Block { return containerNumber; } - @Override - public int computeCaretMaxBound() { - return containerNumber.computeCaretMaxBound(); - } - @Override public Feature toFeature(final MathContext context) throws Error { final Function contnt = getNumberContainer().toFunction(context); @@ -119,7 +104,7 @@ public class BlockSquareRoot extends Block { } @Override - public BlockSquareRoot clone(final TreeContainer parent, InputContext ic) { + public BlockSquareRoot clone(final BlockContainer parent, InputContext ic) { return new BlockSquareRoot(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java index 1cc95935..b3d79eb9 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java @@ -16,7 +16,7 @@ public class BlockUndefined extends Block { recomputeDimensions(); } - private BlockUndefined(final TreeContainer parent, BlockUndefined old, InputContext ic) { + private BlockUndefined(final BlockContainer parent, BlockUndefined old, InputContext ic) { super(parent, old); } @@ -28,20 +28,10 @@ public class BlockUndefined extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { return false; } - @Override - public boolean deleteBlock(final Caret caret) { - return false; - } - - @Override - public BlockReference getBlock(final Caret caret) { - return null; - } - @Override public void recomputeDimensions() { width = BlockContainer.getDefaultFont(small).getStringWidth("UNDEFINED"); @@ -55,11 +45,6 @@ public class BlockUndefined extends Block { recomputeDimensions(); } - @Override - public int computeCaretMaxBound() { - return 0; - } - @Override public Feature toFeature(final MathContext context) { return new FeatureChar(MathematicalSymbols.UNDEFINED); @@ -76,7 +61,7 @@ public class BlockUndefined extends Block { } @Override - public BlockUndefined clone(final TreeContainer parent, InputContext ic) { + public BlockUndefined clone(final BlockContainer parent, InputContext ic) { return new BlockUndefined(parent, this, ic); } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java index 57fb8732..7fdb3679 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java @@ -43,7 +43,7 @@ public class BlockVariable extends Block { recomputeDimensions(); } - private BlockVariable(final TreeContainer parent, BlockVariable old, InputContext ic) { + private BlockVariable(final BlockContainer parent, BlockVariable old, InputContext ic) { super(parent, old); this.ic = ic; this.ch = old.ch; @@ -106,20 +106,10 @@ public class BlockVariable extends Block { } @Override - public boolean appendBlock(final Caret caret, final Block newBlock, boolean splitAdjacent) { + public boolean appendBlock(final Caret caret, final Block newBlock) { return false; } - @Override - public boolean deleteBlock(final Caret caret) { - return false; - } - - @Override - public BlockReference getBlock(final Caret caret) { - return null; - } - @Override public void recomputeDimensions() { width = BlockContainer.getDefaultCharWidth(small); @@ -137,11 +127,6 @@ public class BlockVariable extends Block { return ch; } - @Override - public int computeCaretMaxBound() { - return 0; - } - @Override public ExtraMenu getExtraMenu() { return menu; @@ -271,7 +256,7 @@ public class BlockVariable extends Block { } @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)); } @@ -293,7 +278,7 @@ public class BlockVariable extends Block { } @Override - public BlockVariable clone(final TreeContainer parent, InputContext ic) { + public BlockVariable clone(final BlockContainer parent, InputContext ic) { return new BlockVariable(parent, this, ic); } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java index f631020a..90e1f167 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java @@ -7,10 +7,7 @@ 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.blocks.*; import it.cavallium.warppi.gui.expression.layouts.InputLayout; import it.cavallium.warppi.gui.graphicengine.Renderer; import it.cavallium.warppi.math.Function; @@ -23,7 +20,6 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { 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; @@ -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) { inputContext = ic; - caret = new Caret(CaretState.VISIBLE_ON, 0); 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) { 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.caret = old.caret == null ? null : new Caret(old.caret, root); this.parsed = old.parsed; } @@ -76,14 +71,9 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { 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(); + if (root.appendBlock(caret, b)) { + var innerPos = b.getFirstInnerPosition(); + caret.setPosition(innerPos == null ? new BlockPosition(b) : innerPos); root.recomputeDimensions(); } closeExtra(); @@ -97,13 +87,71 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { } public void del() { - caret.resetRemaining(); - if (root.deleteBlock(caret)) { - root.recomputeDimensions(); + 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 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) { - caret.setPosition(caret.getPosition() - 1); - maxPosition = root.computeCaretMaxBound(); + if (removed) { + while (currentElementToRecompute != null) { + currentElementToRecompute.recomputeDimensions(); + currentElementToRecompute = currentElementToRecompute.getParent(); + } } caret.turnOn(); caretTime = 0; @@ -111,46 +159,25 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { } 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; + 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() { - final int curPos = caret.getPosition(); - if (curPos > 0) { - caret.setPosition(curPos - 1); + var prev = caret.getPos().getPrevious(); + if (prev != null) { + caret.setPosition(prev); } 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.setPosition(new BlockPosition(root.getLastBlock())); } caret.turnOn(); caretTime = 0; @@ -158,7 +185,22 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { } 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 @@ -217,7 +259,6 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { * 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); @@ -225,27 +266,13 @@ public abstract class InputContainer implements GraphicalElement, InputLayout { } public void clear() { - caret = new Caret(CaretState.VISIBLE_ON, 0); + caret = new Caret(CaretState.VISIBLE_ON, new BlockPosition(root)); 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(); + return root.getSize() == 0; } public void setParsed(final boolean parsed) { diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java index 22a64285..641a9e6d 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java @@ -6,6 +6,9 @@ import it.cavallium.warppi.gui.expression.InputContext; import it.cavallium.warppi.gui.expression.blocks.*; import it.cavallium.warppi.math.MathematicalSymbols; +import java.util.ArrayList; +import java.util.List; + public class NormalInputContainer extends InputContainer { @Deprecated() @@ -30,7 +33,6 @@ public class NormalInputContainer extends InputContainer { /** * Copy - * @param userInput * @param ic */ public NormalInputContainer(InputContainer old, InputContext ic) { @@ -93,36 +95,24 @@ public class NormalInputContainer extends InputContainer { switch (c) { case MathematicalSymbols.PARENTHESIS_CLOSE: { final BlockReference ref = getSelectedBlock(); - if (ref == null) { + BlockParenthesisAbstract parenthesis = findParenthesis(ref.get()); + if (parenthesis == null) { break; } else { - final Caret newCaret = new Caret(CaretState.HIDDEN, caret.getPosition()); - 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()); - } + moveTo(new BlockPosition(parenthesis)); } break; } + case MathematicalSymbols.POWER_OF_TWO: + moveTo(new BlockPosition(getSelectedBlock().get())); + break; case MathematicalSymbols.DIVISION: { @SuppressWarnings("unchecked") final BlockReference ref = (BlockReference) getSelectedBlock(); @SuppressWarnings("unused") final BlockContainer parentContainer = ref.getContainer(); BlockReference currentBlock = ref; + List blocksToMove = new ArrayList<>(); boolean groupedBefore = false; int before = 0; while (true) { @@ -135,28 +125,39 @@ public class NormalInputContainer extends InputContainer { if (!groupedBefore) { groupedBefore = true; } + blocksToMove.add(b); before++; } else { break; } } if (groupedBefore) { - moveLeft(); - for (int i = 0; i < before; i++) { - final BlockReference b = getSelectedBlock(); - del(); - moveRight(); - typeBlock(b.get()); - moveLeft(); - moveLeft(); + var div = ref.get(); + var upperContainer = div.getUpperContainer(); + for (int i = blocksToMove.size() - 1; i >= 0; i--) { + var b = blocksToMove.get(i); + b.getParentContainer().removeBlockUnsafe(b); + upperContainer.appendBlock(b); } - for (int i = 0; i < before + 1; i++) { - moveRight(); - } - moveRight();// Move to the divisor + div.recomputeDimensionsToRoot(); + moveTo(new BlockPosition(div.getLowerContainer())); } 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; + } } diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/OutputContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/OutputContainer.java index b320ad18..843d7b55 100644 --- a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/OutputContainer.java +++ b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/OutputContainer.java @@ -6,6 +6,7 @@ import it.cavallium.warppi.gui.expression.Caret; import it.cavallium.warppi.gui.expression.CaretState; import it.cavallium.warppi.gui.expression.blocks.Block; 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.graphicengine.Renderer; 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 { private static final long serialVersionUID = -5714825964892683571L; public final ObjectArrayList roots; - private final Caret caret = new Caret(CaretState.HIDDEN, 0); + private final Caret caret; public OutputContainer() { 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) { 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) { 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 blocks) {