2017-03-03 23:06:43 +01:00
|
|
|
package org.warp.picalculator.gui.expression;
|
|
|
|
|
|
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
|
|
|
2017-04-09 22:01:03 +02:00
|
|
|
import org.warp.picalculator.gui.GraphicalElement;
|
2017-03-03 23:06:43 +01:00
|
|
|
import org.warp.picalculator.gui.graphicengine.BinaryFont;
|
|
|
|
import org.warp.picalculator.gui.graphicengine.GraphicEngine;
|
|
|
|
import org.warp.picalculator.gui.graphicengine.Renderer;
|
|
|
|
|
|
|
|
public class BlockContainer implements GraphicalElement {
|
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
private static boolean initialized = false;
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-04-11 22:04:44 +02:00
|
|
|
private int minWidth;
|
|
|
|
private int minHeight;
|
2017-03-03 23:06:43 +01:00
|
|
|
private final ObjectArrayList<Block> content;
|
|
|
|
private boolean small;
|
|
|
|
private int width;
|
|
|
|
private int height;
|
|
|
|
private int line;
|
2017-03-26 22:44:09 +02:00
|
|
|
public final boolean withBorder;
|
2017-04-11 22:04:44 +02:00
|
|
|
private boolean autoMinimums;
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public BlockContainer() {
|
2017-03-26 22:44:09 +02:00
|
|
|
this(false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true);
|
2017-04-11 22:04:44 +02:00
|
|
|
autoMinimums = true;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public BlockContainer(boolean small) {
|
2017-03-26 22:44:09 +02:00
|
|
|
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true);
|
2017-04-11 22:04:44 +02:00
|
|
|
autoMinimums = true;
|
2017-03-26 22:44:09 +02:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
public BlockContainer(boolean small, boolean withBorder) {
|
|
|
|
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder);
|
2017-04-11 22:04:44 +02:00
|
|
|
autoMinimums = true;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
public BlockContainer(boolean small, int minWidth, int minHeight, boolean withBorder) {
|
|
|
|
this(small, minWidth, minHeight, new ObjectArrayList<>(), withBorder);
|
2017-04-11 22:04:44 +02:00
|
|
|
autoMinimums = false;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
public BlockContainer(boolean small, int minWidth, int minHeight, ObjectArrayList<Block> content, boolean withBorder) {
|
2017-03-03 23:06:43 +01:00
|
|
|
this.small = small;
|
|
|
|
this.minWidth = minWidth;
|
|
|
|
this.minHeight = minHeight;
|
2017-03-26 22:44:09 +02:00
|
|
|
this.withBorder = withBorder;
|
2017-04-10 22:50:43 +02:00
|
|
|
for (final Block b : content) {
|
2017-03-26 22:44:09 +02:00
|
|
|
if (b.isSmall() != small) {
|
|
|
|
b.setSmall(small);
|
|
|
|
}
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
this.content = content;
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
2017-03-26 22:44:09 +02:00
|
|
|
|
|
|
|
public void addBlock(int position, Block b) {
|
|
|
|
if (b.isSmall() != small) {
|
|
|
|
b.setSmall(small);
|
|
|
|
}
|
|
|
|
if (position >= content.size()) {
|
|
|
|
content.add(b);
|
|
|
|
} else {
|
|
|
|
content.add(position, b);
|
|
|
|
}
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
public void appendBlock(Block b) {
|
2017-04-10 22:50:43 +02:00
|
|
|
appendBlockUnsafe(b);
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void appendBlockUnsafe(Block b) {
|
2017-03-26 22:44:09 +02:00
|
|
|
if (b.isSmall() != small) {
|
|
|
|
b.setSmall(small);
|
|
|
|
}
|
2017-03-03 23:06:43 +01:00
|
|
|
content.add(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeBlock(Block b) {
|
|
|
|
content.remove(b);
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeAt(int i) {
|
|
|
|
content.remove(i);
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public Block getBlockAt(int i) {
|
|
|
|
return content.get(i);
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public void clear() {
|
|
|
|
content.clear();
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
/**
|
|
|
|
*
|
2017-04-10 22:50:43 +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.
|
2017-03-03 23:06:43 +01:00
|
|
|
*/
|
|
|
|
public void draw(GraphicEngine ge, Renderer r, int x, int y, Caret caret) {
|
2017-03-26 22:44:09 +02:00
|
|
|
int paddingX = 1;
|
2017-03-03 23:06:43 +01:00
|
|
|
|
|
|
|
if (caret.getRemaining() == 0) {
|
|
|
|
if (content.size() > 0) {
|
2017-04-11 22:04:44 +02:00
|
|
|
BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height);
|
2017-03-03 23:06:43 +01:00
|
|
|
} else {
|
2017-04-11 22:04:44 +02:00
|
|
|
BlockContainer.drawCaret(ge, r, caret, small, x, y, height);
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
if (withBorder && content.size() == 0) {
|
2017-04-10 22:50:43 +02:00
|
|
|
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);
|
2017-03-26 22:44:09 +02:00
|
|
|
} else {
|
2017-04-10 22:50:43 +02:00
|
|
|
for (final Block b : content) {
|
2017-03-26 22:44:09 +02:00
|
|
|
caret.skip(1);
|
2017-04-10 22:50:43 +02:00
|
|
|
b.draw(ge, r, x + paddingX, y + line - b.line, caret);
|
2017-03-26 22:44:09 +02:00
|
|
|
paddingX += b.getWidth();
|
2017-04-10 22:50:43 +02:00
|
|
|
if (caret.getRemaining() == 0) {
|
2017-04-11 22:04:44 +02:00
|
|
|
BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height);
|
2017-04-10 22:50:43 +02:00
|
|
|
}
|
2017-03-26 22:44:09 +02:00
|
|
|
paddingX += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
caret.skip(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean putBlock(Caret caret, Block newBlock) {
|
|
|
|
boolean added = false;
|
|
|
|
|
|
|
|
if (caret.getRemaining() == 0) {
|
2017-04-10 22:50:43 +02:00
|
|
|
addBlock(0, newBlock);
|
2017-03-26 22:44:09 +02:00
|
|
|
added = true;
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
int pos = 0;
|
2017-04-10 22:50:43 +02:00
|
|
|
for (final Block b : content) {
|
2017-03-26 22:44:09 +02:00
|
|
|
caret.skip(1);
|
|
|
|
pos++;
|
2017-04-10 22:50:43 +02:00
|
|
|
added = added | b.putBlock(caret, newBlock);
|
2017-03-26 22:44:09 +02:00
|
|
|
if (caret.getRemaining() == 0) {
|
2017-04-10 22:50:43 +02:00
|
|
|
addBlock(pos, newBlock);
|
2017-03-26 22:44:09 +02:00
|
|
|
added = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
caret.skip(1);
|
|
|
|
if (added) {
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
|
|
|
return added;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean delBlock(Caret caret) {
|
|
|
|
boolean removed = false;
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
int pos = 0;
|
2017-04-10 22:50:43 +02:00
|
|
|
for (final Block b : content) {
|
2017-03-03 23:06:43 +01:00
|
|
|
caret.skip(1);
|
2017-03-26 22:44:09 +02:00
|
|
|
pos++;
|
2017-04-10 22:50:43 +02:00
|
|
|
final int deltaCaret = caret.getRemaining();
|
|
|
|
removed = removed | b.delBlock(caret);
|
2017-03-26 22:44:09 +02:00
|
|
|
if (caret.getRemaining() == 0 || (removed == false && deltaCaret >= 0 && caret.getRemaining() < 0)) {
|
2017-04-10 22:50:43 +02:00
|
|
|
removeAt(pos - 1);
|
|
|
|
caret.setPosition(caret.getPosition() - deltaCaret);
|
2017-03-26 22:44:09 +02:00
|
|
|
removed = true;
|
|
|
|
}
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
caret.skip(1);
|
2017-03-26 22:44:09 +02:00
|
|
|
if (removed) {
|
|
|
|
recomputeDimensions();
|
|
|
|
}
|
|
|
|
return removed;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
2017-04-10 22:50:43 +02:00
|
|
|
|
|
|
|
for (final Block b : content) {
|
2017-03-26 22:44:09 +02:00
|
|
|
w += b.getWidth() + 1;
|
2017-03-03 23:06:43 +01:00
|
|
|
final int bl = b.getLine();
|
|
|
|
final int bh = b.getHeight();
|
|
|
|
final int bh2 = bh - bl;
|
|
|
|
if (bl > l) {
|
|
|
|
l = bl;
|
|
|
|
}
|
|
|
|
if (bh2 > h2) {
|
|
|
|
h2 = bh2;
|
|
|
|
}
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
if (content.size() > 0) {
|
|
|
|
w -= 1;
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
h = h2 + l;
|
|
|
|
|
|
|
|
line = l;
|
|
|
|
if (w > minWidth) {
|
|
|
|
width = w;
|
|
|
|
} else {
|
|
|
|
width = minWidth;
|
|
|
|
}
|
|
|
|
if (h > minHeight) {
|
|
|
|
height = h;
|
|
|
|
} else {
|
|
|
|
height = minHeight;
|
2017-04-10 22:50:43 +02:00
|
|
|
line = height / 2;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@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;
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public static void initializeFonts(BinaryFont big, BinaryFont small) {
|
|
|
|
defFonts[0] = big;
|
|
|
|
defFonts[1] = small;
|
|
|
|
defFontSizes[0] = big.getCharacterWidth();
|
|
|
|
defFontSizes[1] = big.getCharacterHeight();
|
|
|
|
defFontSizes[2] = small.getCharacterWidth();
|
|
|
|
defFontSizes[3] = small.getCharacterHeight();
|
2017-03-26 22:44:09 +02:00
|
|
|
initialized = true;
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public static BinaryFont getDefaultFont(boolean small) {
|
2017-03-26 22:44:09 +02:00
|
|
|
checkInitialized();
|
2017-04-10 22:50:43 +02:00
|
|
|
return defFonts[small ? 1 : 0];
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public static int getDefaultColor() {
|
|
|
|
return defColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int getDefaultCharWidth(boolean b) {
|
2017-03-26 22:44:09 +02:00
|
|
|
checkInitialized();
|
2017-04-10 22:50:43 +02:00
|
|
|
return defFontSizes[b ? 2 : 0];
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
public static int getDefaultCharHeight(boolean b) {
|
2017-03-26 22:44:09 +02:00
|
|
|
checkInitialized();
|
2017-04-10 22:50:43 +02:00
|
|
|
return defFontSizes[b ? 3 : 1];
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-04-11 22:04:44 +02:00
|
|
|
public static void drawCaret(GraphicEngine ge, Renderer r, Caret caret, boolean small, int x, int y, int height) {
|
2017-03-26 22:44:09 +02:00
|
|
|
if (caret.getState() == CaretState.VISIBLE_ON) {
|
|
|
|
r.glColor(getDefaultColor());
|
2017-04-11 22:04:44 +02:00
|
|
|
r.glFillColor(x, y, small?2:3, height);
|
2017-03-26 22:44:09 +02:00
|
|
|
}
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setSmall(boolean small) {
|
|
|
|
this.small = small;
|
2017-04-11 22:04:44 +02:00
|
|
|
if (this.autoMinimums) {
|
|
|
|
this.minWidth = BlockContainer.getDefaultCharWidth(small);
|
|
|
|
this.minHeight = BlockContainer.getDefaultCharHeight(small);
|
|
|
|
}
|
|
|
|
for (Block b : this.content) {
|
|
|
|
b.setSmall(small);
|
|
|
|
}
|
2017-03-03 23:06:43 +01:00
|
|
|
recomputeDimensions();
|
|
|
|
}
|
|
|
|
|
|
|
|
public ObjectArrayList<Block> getContent() {
|
|
|
|
return content.clone();
|
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-26 22:44:09 +02:00
|
|
|
private static void checkInitialized() {
|
2017-04-10 22:50:43 +02:00
|
|
|
if (!initialized) {
|
|
|
|
throw new ExceptionInInitializerError("Please initialize BlockContainer by running the method BlockContainer.initialize(...) first!");
|
|
|
|
}
|
2017-03-26 22:44:09 +02:00
|
|
|
}
|
2017-04-09 22:01:03 +02:00
|
|
|
|
|
|
|
public int computeCaretMaxBound() {
|
|
|
|
int maxpos = 0;
|
2017-04-10 22:50:43 +02:00
|
|
|
for (final Block b : content) {
|
|
|
|
maxpos += 1 + b.computeCaretMaxBound();
|
2017-04-09 22:01:03 +02:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
return maxpos + 1;
|
2017-04-09 22:01:03 +02:00
|
|
|
}
|
2017-04-10 22:50:43 +02:00
|
|
|
|
2017-03-03 23:06:43 +01:00
|
|
|
}
|