WarpPI/src/org/warp/picalculator/gui/screens/MathInputScreen.java

609 lines
17 KiB
Java
Raw Normal View History

package org.warp.picalculator.gui.screens;
2016-09-02 20:32:37 +02:00
import java.io.IOException;
2016-09-02 20:32:37 +02:00
import java.io.PrintWriter;
import java.io.StringWriter;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
2017-01-16 17:57:09 +01:00
import java.util.Collections;
import java.util.Iterator;
2017-01-16 17:57:09 +01:00
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
2016-09-02 20:32:37 +02:00
import org.warp.picalculator.Error;
import org.warp.picalculator.Errors;
import org.warp.picalculator.Main;
2016-09-02 20:32:37 +02:00
import org.warp.picalculator.Utils;
import org.warp.picalculator.device.Keyboard;
import org.warp.picalculator.device.Keyboard.Key;
import org.warp.picalculator.gui.DisplayManager;
import org.warp.picalculator.gui.expression.BlockContainer;
import org.warp.picalculator.gui.expression.containers.InputContainer;
import org.warp.picalculator.gui.expression.containers.NormalInputContainer;
import org.warp.picalculator.gui.expression.containers.NormalOutputContainer;
import org.warp.picalculator.gui.expression.containers.OutputContainer;
import org.warp.picalculator.gui.graphicengine.BinaryFont;
import org.warp.picalculator.gui.graphicengine.Renderer;
2017-01-16 17:57:09 +01:00
import org.warp.picalculator.math.AngleMode;
import org.warp.picalculator.math.MathContext;
import org.warp.picalculator.math.Function;
import org.warp.picalculator.math.FunctionDynamic;
import org.warp.picalculator.math.FunctionSingle;
import org.warp.picalculator.math.FunctionOperator;
import org.warp.picalculator.math.MathematicalSymbols;
2017-01-16 17:57:09 +01:00
import org.warp.picalculator.math.functions.Variable;
import org.warp.picalculator.math.functions.Variable.VariableValue;
import org.warp.picalculator.math.functions.equations.Equation;
import org.warp.picalculator.math.functions.Number;
2016-11-02 21:56:40 +01:00
2016-12-04 22:22:16 +01:00
public class MathInputScreen extends Screen {
2016-09-02 20:32:37 +02:00
public MathContext calc;
public InputContainer userInput;
public OutputContainer result;
2016-09-02 20:32:37 +02:00
public int errorLevel = 0; // 0 = nessuno, 1 = risultato, 2 = tutto
boolean mustRefresh = true;
2016-12-04 22:22:16 +01:00
public MathInputScreen() {
2016-09-02 20:32:37 +02:00
super();
canBeInHistory = true;
}
2016-09-02 20:32:37 +02:00
@Override
public void created() throws InterruptedException {
calc = new MathContext();
try {
BlockContainer.initializeFonts(DisplayManager.engine.loadFont("ex"), DisplayManager.engine.loadFont("big"));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
userInput = new NormalInputContainer();
result = new NormalOutputContainer();
calc.init();
2016-09-02 20:32:37 +02:00
}
@Override
public void init() throws InterruptedException {
2016-10-02 16:01:41 +02:00
/* Fine caricamento */
2016-09-02 20:32:37 +02:00
}
2016-09-02 20:32:37 +02:00
@Override
public void beforeRender(float dt) {
if (DisplayManager.error == null) {
DisplayManager.renderer.glClearColor(0xFFc5c2af);
} else {
DisplayManager.renderer.glClearColor(0xFFDC3C32);
}
if (userInput.beforeRender(dt)) {
mustRefresh = true;
}
2016-09-02 20:32:37 +02:00
}
private static final BinaryFont fontBig = Utils.getFont(false);
@Override
public void renderStatusbar() {
Renderer renderer = DisplayManager.renderer;
renderer.glColor3f(1, 1, 1);
final int pos = 2;
final int spacersNumb = 1;
int skinN = 0;
if (calc.exactMode) {
skinN = 22;
} else {
skinN = 21;
}
renderer.glFillRect(2 + 18 * pos + 2 * spacersNumb, 2, 16, 16, 16 * skinN, 16 * 0, 16, 16);
}
2016-09-02 20:32:37 +02:00
@Override
public void render() {
fontBig.use(DisplayManager.engine);
final int textColor = 0xFF000000;
final int padding = 4;
DisplayManager.renderer.glColor(textColor);
userInput.draw(DisplayManager.engine, DisplayManager.renderer, padding, padding + 20);
if (!result.root.getContent().isEmpty()) {
result.draw(DisplayManager.engine, DisplayManager.renderer, DisplayManager.engine.getWidth() - 2, DisplayManager.engine.getHeight() - 2);
}
2016-09-02 20:32:37 +02:00
}
@Override
public boolean mustBeRefreshed() {
if (mustRefresh) {
mustRefresh = false;
return true;
} else {
return false;
}
}
@Override
public boolean keyPressed(Key k) {
switch (k) {
case STEP:
// if (newExpression.length() > 0) {
// if (firstStep) {
// try {
// try {
// interpreta(true);
// showVariablesDialog(() -> {
// currentExpression = newExpression;
// calc.f2 = calc.f;
// firstStep = false;
// step();
// });
// } catch (final Exception ex) {
// if (Utils.debugOn) {
// ex.printStackTrace();
// }
// throw new Error(Errors.SYNTAX_ERROR);
// }
// } catch (final Error e) {
// final StringWriter sw = new StringWriter();
// final PrintWriter pw = new PrintWriter(sw);
// e.printStackTrace(pw);
// d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
// DisplayManager.error = e.id.toString();
// System.err.println(e.id);
// }
// } else {
// step();
// }
// }
// return true;
case SIMPLIFY:
// if (DisplayManager.error != null) {
// Utils.debug.println("Resetting after error...");
// DisplayManager.error = null;
// currentExpression = null;
// calc.f = null;
// calc.f2 = null;
// calc.resultsCount = 0;
// return true;
// } else {
// try {
// try {
// if (!firstStep) {
// step();
// } else {
// if (newExpression != currentExpression && newExpression.length() > 0) {
// changeEquationScreen();
// interpreta(true);
// showVariablesDialog(() -> {
// currentExpression = newExpression;
// simplify();
// });
// }
// }
// } catch (final Exception ex) {
// if (Utils.debugOn) {
// ex.printStackTrace();
// }
// throw new Error(Errors.SYNTAX_ERROR);
// }
// } catch (final Error e) {
// final StringWriter sw = new StringWriter();
// final PrintWriter pw = new PrintWriter(sw);
// e.printStackTrace(pw);
// d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
// DisplayManager.error = e.id.toString();
// System.err.println(e.id);
// }
// return true;
// }
return true;
2016-09-02 20:32:37 +02:00
case NUM0:
typeChar('0');
2016-09-02 20:32:37 +02:00
return true;
case NUM1:
typeChar('1');
2016-09-02 20:32:37 +02:00
return true;
case NUM2:
typeChar('2');
2016-09-02 20:32:37 +02:00
return true;
case NUM3:
typeChar('3');
2016-09-02 20:32:37 +02:00
return true;
case NUM4:
typeChar('4');
2016-09-02 20:32:37 +02:00
return true;
case NUM5:
typeChar('5');
2016-09-02 20:32:37 +02:00
return true;
case NUM6:
typeChar('6');
2016-09-02 20:32:37 +02:00
return true;
case NUM7:
typeChar('7');
2016-09-02 20:32:37 +02:00
return true;
case NUM8:
typeChar('8');
2016-09-02 20:32:37 +02:00
return true;
case NUM9:
typeChar('9');
2016-09-02 20:32:37 +02:00
return true;
case PLUS:
typeChar('+');
2016-09-02 20:32:37 +02:00
return true;
case MINUS:
typeChar('-');
2016-09-02 20:32:37 +02:00
return true;
case PLUS_MINUS:
typeChar('±');
return true;
2016-09-02 20:32:37 +02:00
case MULTIPLY:
typeChar('*');
2016-09-02 20:32:37 +02:00
return true;
case DIVIDE:
typeChar('/');
2016-09-02 20:32:37 +02:00
return true;
case PARENTHESIS_OPEN:
typeChar('(');
2016-09-02 20:32:37 +02:00
return true;
case PARENTHESIS_CLOSE:
typeChar(')');
2016-09-02 20:32:37 +02:00
return true;
case DOT:
typeChar('.');
2016-09-02 20:32:37 +02:00
return true;
case EQUAL:
typeChar('=');
2016-09-02 20:32:37 +02:00
return true;
case SQRT:
typeChar('â’¶');
2016-09-02 20:32:37 +02:00
return true;
case ROOT:
typeChar('√');
2016-09-02 20:32:37 +02:00
return true;
case POWER_OF_2:
typeChar(MathematicalSymbols.POWER_OF_TWO);
2016-09-02 20:32:37 +02:00
return true;
case POWER_OF_x:
2016-12-04 22:22:16 +01:00
typeChar(MathematicalSymbols.POWER);
2016-09-02 20:32:37 +02:00
return true;
2017-01-16 17:57:09 +01:00
case PI:
typeChar(MathematicalSymbols.PI);
return true;
case LETTER_X:
typeChar(MathematicalSymbols.variables[23]);
return true;
case LETTER_Y:
typeChar(MathematicalSymbols.variables[24]);
return true;
2016-12-04 22:22:16 +01:00
case SINE:
typeChar(MathematicalSymbols.SINE);
return true;
case COSINE:
typeChar(MathematicalSymbols.COSINE);
return true;
case TANGENT:
typeChar(MathematicalSymbols.TANGENT);
return true;
case ARCSINE:
typeChar(MathematicalSymbols.ARC_SINE);
return true;
case ARCCOSINE:
typeChar(MathematicalSymbols.ARC_COSINE);
return true;
case ARCTANGENT:
typeChar(MathematicalSymbols.ARC_TANGENT);
return true;
2016-09-02 20:32:37 +02:00
case DELETE:
userInput.del();
mustRefresh = true;
2016-09-02 20:32:37 +02:00
return true;
case LEFT:
userInput.moveLeft();
mustRefresh = true;
2016-09-02 20:32:37 +02:00
return true;
case RIGHT:
userInput.moveRight();
mustRefresh = true;
2016-09-02 20:32:37 +02:00
return true;
case RESET:
userInput.clear();
result.clear();
if (DisplayManager.error != null) {
2016-09-02 20:32:37 +02:00
Utils.debug.println("Resetting after error...");
DisplayManager.error = null;
2016-09-02 20:32:37 +02:00
}
return true;
case SURD_MODE:
// calc.exactMode = !calc.exactMode;
// if (calc.exactMode == false) {
// calc.f2 = solveExpression(calc.f2);
// } else {
// currentExpression = "";
// Keyboard.keyPressed(Key.SIMPLIFY);
// }
return true;
2016-09-02 20:32:37 +02:00
case debug1:
DisplayManager.INSTANCE.setScreen(new EmptyScreen());
2016-09-02 20:32:37 +02:00
return true;
case HISTORY_BACK:
// if (DisplayManager.INSTANCE.canGoBack()) {
// if (currentExpression != null && currentExpression.length() > 0 & DisplayManager.sessions[DisplayManager.currentSession + 1] instanceof MathInputScreen) {
// newExpression = currentExpression;
// try {
// interpreta(true);
// } catch (final Error e) {}
// }
// }
return false;
case HISTORY_FORWARD:
// if (DisplayManager.INSTANCE.canGoForward()) {
// if (currentExpression != null && currentExpression.length() > 0 & DisplayManager.sessions[DisplayManager.currentSession - 1] instanceof MathInputScreen) {
// newExpression = currentExpression;
// try {
// interpreta(true);
// } catch (final Error e) {}
// }
// }
return false;
2017-01-16 17:57:09 +01:00
case debug_DEG:
if (calc.angleMode.equals(AngleMode.DEG) == false) {
calc.angleMode = AngleMode.DEG;
return true;
}
return false;
case debug_RAD:
if (calc.angleMode.equals(AngleMode.RAD) == false) {
calc.angleMode = AngleMode.RAD;
return true;
}
return false;
case debug_GRA:
if (calc.angleMode.equals(AngleMode.GRA) == false) {
calc.angleMode = AngleMode.GRA;
return true;
}
return false;
case DRG_CYCLE:
if (calc.angleMode.equals(AngleMode.DEG) == true) {
calc.angleMode = AngleMode.RAD;
} else if (calc.angleMode.equals(AngleMode.RAD) == true) {
calc.angleMode = AngleMode.GRA;
} else {
calc.angleMode = AngleMode.DEG;
}
return true;
2016-09-02 20:32:37 +02:00
default:
return false;
}
}
private ObjectArrayList<Function> solveExpression(ObjectArrayList<Function> f22) {
2017-01-16 17:57:09 +01:00
try {
try {
return calc.solveExpression(f22);
} catch (final Exception ex) {
2017-01-16 17:57:09 +01:00
if (Utils.debugOn) {
ex.printStackTrace();
}
throw new Error(Errors.SYNTAX_ERROR);
}
} catch (final Error e) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
2017-01-16 17:57:09 +01:00
e.printStackTrace(pw);
d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
DisplayManager.error = e.id.toString();
2017-01-16 17:57:09 +01:00
System.err.println(e.id);
}
return null;
}
protected void step() {
2017-01-16 17:57:09 +01:00
try {
try {
showVariablesDialog();
ObjectArrayList<Function> results = new ObjectArrayList<>();
final ObjectArrayList<Function> partialResults = new ObjectArrayList<>();
for (final Function f : calc.f2) {
2017-01-16 17:57:09 +01:00
if (f instanceof Equation) {
DisplayManager.INSTANCE.setScreen(new SolveEquationScreen(this));
2017-01-16 17:57:09 +01:00
} else {
results.add(f);
for (final Function itm : results) {
if (itm.isSimplified() == false) {
final List<Function> dt = itm.simplify();
2017-01-16 17:57:09 +01:00
partialResults.addAll(dt);
} else {
partialResults.add(itm);
}
}
results = new ObjectArrayList<>(partialResults);
2017-01-16 17:57:09 +01:00
partialResults.clear();
}
}
2017-01-16 17:57:09 +01:00
if (results.size() == 0) {
2017-01-17 22:32:40 +01:00
calc.resultsCount = 0;
2017-01-16 17:57:09 +01:00
} else {
2017-01-17 22:32:40 +01:00
calc.resultsCount = results.size();
2017-01-16 17:57:09 +01:00
Collections.reverse(results);
// add elements to al, including duplicates
final Set<Function> hs = new LinkedHashSet<>();
2017-01-16 17:57:09 +01:00
hs.addAll(results);
results.clear();
results.addAll(hs);
2017-01-17 22:32:40 +01:00
calc.f2 = results;
for (final Function rf : calc.f2) {
rf.recomputeDimensions(null);
2017-01-16 17:57:09 +01:00
}
}
2017-02-02 12:49:31 +01:00
Utils.debug.println(calc.f2.toString());
} catch (final Exception ex) {
2017-01-16 17:57:09 +01:00
if (Utils.debugOn) {
ex.printStackTrace();
}
throw new Error(Errors.SYNTAX_ERROR);
}
} catch (final Error e) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
2017-01-16 17:57:09 +01:00
e.printStackTrace(pw);
d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
DisplayManager.error = e.id.toString();
2017-01-16 17:57:09 +01:00
System.err.println(e.id);
}
}
protected void simplify() {
2017-01-16 17:57:09 +01:00
try {
try {
for (final Function f : calc.f) {
2017-01-16 17:57:09 +01:00
if (f instanceof Equation) {
DisplayManager.INSTANCE.setScreen(new SolveEquationScreen(this));
2017-01-16 17:57:09 +01:00
return;
}
}
final ObjectArrayList<Function> results = solveExpression(calc.f);
2017-01-16 17:57:09 +01:00
if (results.size() == 0) {
2017-01-17 22:32:40 +01:00
calc.resultsCount = 0;
2017-01-16 17:57:09 +01:00
} else {
2017-01-17 22:32:40 +01:00
calc.resultsCount = results.size();
2017-01-16 17:57:09 +01:00
Collections.reverse(results);
// add elements to al, including duplicates
final Set<Function> hs = new LinkedHashSet<>();
2017-01-16 17:57:09 +01:00
hs.addAll(results);
results.clear();
results.addAll(hs);
2017-01-17 22:32:40 +01:00
calc.f2 = results;
for (final Function rf : calc.f2) {
rf.recomputeDimensions(null);
2017-01-16 17:57:09 +01:00
}
}
} catch (final Exception ex) {
2017-01-16 17:57:09 +01:00
if (Utils.debugOn) {
ex.printStackTrace();
}
throw new Error(Errors.SYNTAX_ERROR);
}
} catch (final Error e) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
2017-01-16 17:57:09 +01:00
e.printStackTrace(pw);
d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
DisplayManager.error = e.id.toString();
2017-01-16 17:57:09 +01:00
System.err.println(e.id);
}
}
2016-11-02 21:56:40 +01:00
private void changeEquationScreen() {
if (currentExpression != null && currentExpression.length() > 0) {
final MathInputScreen cloned = clone();
cloned.caretPos = cloned.currentExpression.length();
cloned.newExpression = cloned.currentExpression;
cloned.scrollX = fontBig.getStringWidth(cloned.currentExpression);
try {
cloned.interpreta(true);
} catch (final Error e) {}
DisplayManager.INSTANCE.replaceScreen(cloned);
initialized = false;
DisplayManager.INSTANCE.setScreen(this);
2016-11-02 21:56:40 +01:00
}
}
public void typeChar(char chr) {
userInput.typeChar(chr);
mustRefresh = true;
2016-09-02 20:32:37 +02:00
}
2016-09-02 20:32:37 +02:00
@Override
public boolean keyReleased(Key k) {
return false;
}
2017-01-17 22:32:40 +01:00
public void showVariablesDialog() {
showVariablesDialog(null);
}
2017-01-16 17:57:09 +01:00
public void showVariablesDialog(final Runnable runnable) {
final Thread ct = new Thread(() -> {
final ObjectArrayList<Function> knownVarsInFunctions = getKnownVariables(calc.f.toArray(new Function[calc.f.size()]));
for (final VariableValue f : calc.variablesValues) {
if (knownVarsInFunctions.contains(f.v)) {
knownVarsInFunctions.remove(f.v);
2017-01-16 17:57:09 +01:00
}
}
2017-01-16 17:57:09 +01:00
boolean cancelled = false;
for (final Function f : knownVarsInFunctions) {
final ChooseVariableValueScreen cvs = new ChooseVariableValueScreen(this, new VariableValue((Variable) f, new Number(calc, 0)));
DisplayManager.INSTANCE.setScreen(cvs);
2017-01-16 17:57:09 +01:00
try {
while (DisplayManager.screen == cvs) {
2017-01-16 17:57:09 +01:00
Utils.debug.println(Thread.currentThread().getName());
Thread.sleep(200);
}
} catch (final InterruptedException e) {}
2017-01-16 17:57:09 +01:00
if (cvs.resultNumberValue == null) {
cancelled = true;
break;
} else {
2017-01-17 22:32:40 +01:00
final int is = calc.variablesValues.size();
2017-01-16 17:57:09 +01:00
for (int i = 0; i < is; i++) {
2017-01-17 22:32:40 +01:00
if (calc.variablesValues.get(i).v == f) {
calc.variablesValues.remove(i);
2017-01-16 17:57:09 +01:00
}
}
2017-01-17 22:32:40 +01:00
calc.variablesValues.add(new VariableValue((Variable) f, (Number) cvs.resultNumberValue));
2017-01-16 17:57:09 +01:00
}
}
if (!cancelled) {
2017-01-17 22:32:40 +01:00
if (runnable != null) {
runnable.run();
}
2017-01-16 17:57:09 +01:00
}
});
ct.setName("Variables user-input queue thread");
ct.setPriority(Thread.MIN_PRIORITY);
ct.setDaemon(true);
ct.start();
}
private ObjectArrayList<Function> getKnownVariables(Function[] fncs) {
final ObjectArrayList<Function> res = new ObjectArrayList<>();
for (final Function f : fncs) {
if (f instanceof FunctionOperator) {
res.addAll(getKnownVariables(new Function[] { ((FunctionOperator) f).getParameter1(), ((FunctionOperator) f).getParameter2() }));
} else if (f instanceof FunctionDynamic) {
res.addAll(getKnownVariables(((FunctionDynamic) f).getParameters()));
} else if (f instanceof FunctionSingle) {
res.addAll(getKnownVariables(new Function[] { ((FunctionSingle) f).getParameter() }));
2017-01-16 17:57:09 +01:00
} else if (f instanceof Variable) {
if (((Variable)f).getType() == Variable.V_TYPE.KNOWN) {
if (!res.contains(f)) {
res.add(f);
}
2017-01-16 17:57:09 +01:00
}
}
}
return res;
}
2016-11-02 21:56:40 +01:00
@Override
2016-12-04 22:22:16 +01:00
public MathInputScreen clone() {
final MathInputScreen es = this;
final MathInputScreen es2 = new MathInputScreen();
2016-11-02 21:56:40 +01:00
es2.errorLevel = es.errorLevel;
es2.mustRefresh = es.mustRefresh;
2017-01-17 22:32:40 +01:00
es2.calc = Utils.cloner.deepClone(es.calc);
es2.userInput = Utils.cloner.deepClone(es.userInput);
es2.result = Utils.cloner.deepClone(es.result);
2016-11-02 21:56:40 +01:00
return es2;
}
2016-09-02 20:32:37 +02:00
}