WarpPI/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java

364 lines
10 KiB
Java
Raw Normal View History

package it.cavallium.warppi.gui.expression.blocks;
2018-09-04 12:12:41 +02:00
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.gui.GraphicalElement;
import it.cavallium.warppi.gui.expression.Caret;
import it.cavallium.warppi.gui.expression.CaretState;
import it.cavallium.warppi.gui.graphicengine.BinaryFont;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Renderer;
import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.parser.MathParser;
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;
public class BlockContainer implements GraphicalElement {
private static boolean initialized = false;
private int minWidth;
private int minHeight;
private final ObjectArrayList<Block> content;
private boolean small;
private int width;
private int height;
private int line;
public final boolean withBorder;
private boolean autoMinimums;
public BlockContainer() {
this(false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true);
autoMinimums = true;
}
2018-09-22 11:17:30 +02:00
public BlockContainer(final boolean small) {
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true);
autoMinimums = true;
}
2018-09-22 11:17:30 +02:00
public BlockContainer(final boolean small, final ObjectArrayList<Block> content) {
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), content, true);
autoMinimums = true;
}
2018-09-22 11:17:30 +02:00
public BlockContainer(final boolean small, final boolean withBorder) {
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder);
autoMinimums = true;
}
2018-09-22 11:17:30 +02:00
public BlockContainer(final boolean small, final int minWidth, final int minHeight, final boolean withBorder) {
this(small, minWidth, minHeight, new ObjectArrayList<>(), withBorder);
autoMinimums = false;
}
2018-09-22 11:17:30 +02:00
public BlockContainer(final boolean small, final int minWidth, final int minHeight, final ObjectArrayList<Block> content, final boolean withBorder) {
this.small = small;
this.minWidth = minWidth;
this.minHeight = minHeight;
this.withBorder = withBorder;
2018-09-22 11:17:30 +02:00
for (final Block b : content)
if (b.isSmall() != small)
b.setSmall(small);
this.content = content;
recomputeDimensions();
}
2018-09-22 11:17:30 +02:00
public void addBlock(final int position, final Block b) {
2018-03-11 21:49:41 +01:00
addBlockUnsafe(position, b);
recomputeDimensions();
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public void addBlockUnsafe(final int position, final Block b) {
if (b.isSmall() != small)
b.setSmall(small);
2018-09-22 11:17:30 +02:00
if (position >= content.size())
content.add(b);
2018-09-22 11:17:30 +02:00
else
content.add(position, b);
}
2018-09-22 11:17:30 +02:00
public void appendBlock(final Block b) {
appendBlockUnsafe(b);
recomputeDimensions();
}
2018-09-22 11:17:30 +02:00
public void appendBlockUnsafe(final Block b) {
if (b.isSmall() != small)
b.setSmall(small);
content.add(b);
}
2018-09-22 11:17:30 +02:00
public void removeBlock(final Block b) {
2018-03-11 21:49:41 +01:00
removeBlockUnsafe(b);
recomputeDimensions();
}
2018-09-22 11:17:30 +02:00
public void removeBlockUnsafe(final Block b) {
2018-03-11 21:49:41 +01:00
content.remove(b);
}
2018-09-22 11:17:30 +02:00
public void removeAt(final int i) {
content.remove(i);
recomputeDimensions();
}
2018-09-22 11:17:30 +02:00
public BlockReference<?> getBlockAt(final int i) {
2018-05-12 21:18:29 +02:00
final Block b = content.get(i);
2018-03-11 21:49:41 +01:00
return new BlockReference<>(b, i, this);
}
public int getSize() {
return content.size();
}
public void clear() {
content.clear();
recomputeDimensions();
}
/**
2018-09-22 11:17:30 +02:00
*
* @param ge
* Graphic Engine class.
* @param r
* Graphic Renderer class of <b>ge</b>.
* @param x
* Position relative to the window.
* @param y
* Position relative to the window.
* @param caret
* Position of the caret.
*/
2018-09-22 11:17:30 +02:00
public void draw(final GraphicEngine ge, final Renderer r, final int x, final int y, final Caret caret) {
int paddingX = 1;
2018-09-22 11:17:30 +02:00
if (caret.getRemaining() == 0)
if (content.size() > 0)
BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height);
2018-09-22 11:17:30 +02:00
else
BlockContainer.drawCaret(ge, r, caret, small, x, y, height);
if (withBorder && content.size() == 0) {
r.glColor(BlockContainer.getDefaultColor());
r.glDrawLine(x + paddingX, y, x + paddingX + width - 1, y);
r.glDrawLine(x + paddingX, y, x + paddingX, y + height - 1);
r.glDrawLine(x + paddingX + width - 1, y, x + paddingX + width - 1, y + height - 1);
r.glDrawLine(x + paddingX, y + height - 1, x + paddingX + width - 1, y + height - 1);
2018-09-22 11:17:30 +02:00
} else
for (final Block b : content) {
caret.skip(1);
b.draw(ge, r, x + paddingX, y + line - b.line, caret);
paddingX += b.getWidth();
2018-09-22 11:17:30 +02:00
if (caret.getRemaining() == 0)
BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height);
paddingX += 1;
}
caret.skip(1);
}
2018-09-22 11:17:30 +02:00
public boolean putBlock(final Caret caret, final Block newBlock) {
boolean added = false;
if (caret.getRemaining() == 0) {
addBlock(0, newBlock);
added = true;
}
int pos = 0;
for (final Block b : content) {
caret.skip(1);
pos++;
added = added | b.putBlock(caret, newBlock);
if (caret.getRemaining() == 0) {
addBlock(pos, newBlock);
added = true;
}
}
caret.skip(1);
2018-09-22 11:17:30 +02:00
if (added)
recomputeDimensions();
return added;
}
2018-09-22 11:17:30 +02:00
public boolean delBlock(final Caret caret) {
boolean removed = false;
int pos = 0;
for (final Block b : content) {
caret.skip(1);
pos++;
final int deltaCaret = caret.getRemaining();
removed = removed | b.delBlock(caret);
2018-09-22 11:17:30 +02:00
if (caret.getRemaining() == 0 || removed == false && deltaCaret >= 0 && caret.getRemaining() < 0) {
removeAt(pos - 1);
caret.setPosition(caret.getPosition() - deltaCaret);
removed = true;
}
}
caret.skip(1);
2018-09-22 11:17:30 +02:00
if (removed)
recomputeDimensions();
return removed;
}
2018-09-22 11:17:30 +02:00
public BlockReference<?> getBlock(final Caret caret) {
2018-03-11 21:49:41 +01:00
BlockReference<?> block = null;
int pos = 0;
for (final Block b : content) {
caret.skip(1);
pos++;
final int deltaCaret = caret.getRemaining();
block = b.getBlock(caret);
2018-09-22 11:17:30 +02:00
if (block != null)
2017-06-05 22:50:33 +02:00
return block;
2018-09-22 11:17:30 +02:00
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
int w = 0; //Width
int h2 = 0; //Height under the line. h = h2 + l
int h = 0; //Height
for (final Block b : content) {
w += b.getWidth() + 1;
final int bl = b.getLine();
final int bh = b.getHeight();
final int bh2 = bh - bl;
2018-09-22 11:17:30 +02:00
if (bl > l)
l = bl;
2018-09-22 11:17:30 +02:00
if (bh2 > h2)
h2 = bh2;
}
2018-09-22 11:17:30 +02:00
if (content.size() > 0)
w -= 1;
h = h2 + l;
line = l;
2018-09-22 11:17:30 +02:00
if (w > minWidth)
width = w;
2018-09-22 11:17:30 +02:00
else
width = minWidth;
2018-09-22 11:17:30 +02:00
if (h > minHeight)
height = h;
2018-09-22 11:17:30 +02:00
else {
height = minHeight;
line = height / 2;
}
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public int getLine() {
return line;
}
private static final BinaryFont[] defFonts = new BinaryFont[2];
private static final int[] defFontSizes = new int[4];
private static final int defColor = 0xFF000000;
2018-09-22 11:17:30 +02:00
public static void initializeFonts(final BinaryFont big, final BinaryFont small) {
BlockContainer.defFonts[0] = big;
BlockContainer.defFonts[1] = small;
BlockContainer.defFontSizes[0] = big.getCharacterWidth();
BlockContainer.defFontSizes[1] = big.getCharacterHeight();
BlockContainer.defFontSizes[2] = small.getCharacterWidth();
BlockContainer.defFontSizes[3] = small.getCharacterHeight();
BlockContainer.initialized = true;
}
2018-09-22 11:17:30 +02:00
public static BinaryFont getDefaultFont(final boolean small) {
BlockContainer.checkInitialized();
return BlockContainer.defFonts[small ? 1 : 0];
}
public static int getDefaultColor() {
2018-09-22 11:17:30 +02:00
return BlockContainer.defColor;
}
2018-09-22 11:17:30 +02:00
public static int getDefaultCharWidth(final boolean b) {
BlockContainer.checkInitialized();
return BlockContainer.defFontSizes[b ? 2 : 0];
}
2018-09-22 11:17:30 +02:00
public static int getDefaultCharHeight(final boolean b) {
BlockContainer.checkInitialized();
return BlockContainer.defFontSizes[b ? 3 : 1];
}
2018-09-22 11:17:30 +02:00
public static void drawCaret(final GraphicEngine ge, final Renderer r, final Caret caret, final boolean small,
final int x, final int y, final int height) {
if (caret.getState() == CaretState.VISIBLE_ON) {
2018-09-22 11:17:30 +02:00
r.glColor(BlockContainer.getDefaultColor());
r.glFillColor(x, y, small ? 2 : 3, height);
caret.setLastLocation(x, y);
caret.setLastSize(small ? 2 : 3, height);
}
}
2018-09-22 11:17:30 +02:00
public void setSmall(final boolean small) {
this.small = small;
2018-05-12 21:18:29 +02:00
if (autoMinimums) {
minWidth = BlockContainer.getDefaultCharWidth(small);
minHeight = BlockContainer.getDefaultCharHeight(small);
}
2018-09-22 11:17:30 +02:00
for (final Block b : content)
b.setSmall(small);
recomputeDimensions();
}
public ObjectArrayList<Block> getContent() {
return content.clone();
}
private static void checkInitialized() {
2018-09-22 11:17:30 +02:00
if (!BlockContainer.initialized)
2018-09-04 12:12:41 +02:00
Engine.getPlatform().throwNewExceptionInInitializerError("Please initialize BlockContainer by running the method BlockContainer.initialize(...) first!");
}
2017-04-09 22:01:03 +02:00
public int computeCaretMaxBound() {
int maxpos = 0;
2018-09-22 11:17:30 +02:00
for (final Block b : content)
maxpos += 1 + b.computeCaretMaxBound();
return maxpos + 1;
2017-04-09 22:01:03 +02:00
}
2018-09-22 11:17:30 +02:00
public Function toFunction(final MathContext context) throws Error {
2018-05-12 21:18:29 +02:00
final ObjectArrayList<Block> blocks = getContent();
final ObjectArrayList<Feature> blockFeatures = new ObjectArrayList<>();
for (final Block block : blocks) {
final Feature blockFeature = block.toFeature(context);
2018-09-22 11:17:30 +02:00
if (blockFeature == null)
throw new Error(Errors.NOT_IMPLEMENTED, "The block " + block.getClass().getSimpleName() + " isn't a known Block");
blockFeatures.add(blockFeature);
}
final Function result = MathParser.joinFeatures(context, blockFeatures);
return result;
}
}