mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Git] Fix conflicts
This commit is contained in:
2
.github/workflows/ci-workflow.yml
vendored
2
.github/workflows/ci-workflow.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-simulator-web.zip
|
||||
path: output/release/simulator/web/simulator.zip
|
||||
path: output/release/simulator/web/epsilon.zip
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web test.headless.js
|
||||
build-simulator-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@
|
||||
build/device/**/*.pyc
|
||||
epsilon.elf
|
||||
.vscode
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
.gradle
|
||||
|
||||
@@ -16,7 +16,7 @@ Omega is a fork of Numworks' Epsilon, the OS that runs on their calculator, whic
|
||||
- An app for RPN
|
||||
- A periodic table app + all of the molar masses for the elements in the toolbox
|
||||
- More steps for brightness (16 instead of 5)
|
||||
- 32 KB Python heap instead of 16 KB
|
||||
- ~~32 KB Python heap instead of 16 KB~~ Now available on Epsilon `>=13.2.0`!
|
||||
- And more...
|
||||
|
||||
The main new features are listed [here](https://github.com/Omega-Numworks/Omega/wiki/Main-features), and the complete changelog can be found [here](https://github.com/quentinguidee/Omega/wiki/Complete-changelog).
|
||||
|
||||
@@ -6,7 +6,7 @@ using namespace Poincare;
|
||||
namespace Calculation {
|
||||
|
||||
ComplexGraphView::ComplexGraphView(ComplexModel * complexModel) :
|
||||
CurveView(complexModel),
|
||||
LabeledCurveView(complexModel),
|
||||
m_complex(complexModel)
|
||||
{
|
||||
}
|
||||
@@ -24,13 +24,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
float imag = m_complex->imag();
|
||||
|
||||
assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag));
|
||||
/* Draw the segment from the origin to the dot (real, imag) of equation
|
||||
* x(t) = t*real and y(t) = t*imag with t in [0,1] */
|
||||
drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f,
|
||||
[](float t, void * model, void * context) {
|
||||
ComplexModel * complexModel = (ComplexModel *)model;
|
||||
return Poincare::Coordinate2D<float>(complexModel->real()*t, complexModel->imag()*t);
|
||||
}, m_complex, nullptr, false, Palette::GreyDark, false);
|
||||
// Draw the segment from the origin to the dot (real, imag)
|
||||
drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::GreyDark, false);
|
||||
|
||||
/* Draw the partial ellipse indicating the angle θ
|
||||
* - the ellipse parameters are a = |real|/5 and b = |imag|/5,
|
||||
@@ -66,8 +61,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
}, ¶meters, &th, false, Palette::GreyDark, false);
|
||||
|
||||
// Draw dashed segment to indicate real and imaginary
|
||||
drawSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
|
||||
|
||||
// Draw complex position on the plan
|
||||
drawDot(ctx, rect, real, imag, Palette::Red, Size::Large);
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H
|
||||
#define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H
|
||||
|
||||
#include "../../shared/curve_view.h"
|
||||
#include "../../shared/labeled_curve_view.h"
|
||||
#include "complex_model.h"
|
||||
#include "illustration_cell.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class ComplexGraphView : public Shared::CurveView {
|
||||
class ComplexGraphView : public Shared::LabeledCurveView {
|
||||
public:
|
||||
ComplexGraphView(ComplexModel * complexModel);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override {
|
||||
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
|
||||
}
|
||||
// '-' + significant digits + ".E-" + 2 digits (the represented dot is a float, so it is bounded by 1E38 and 1E-38
|
||||
size_t labelMaxGlyphLengthSize() const override { return 1 + Poincare::Preferences::VeryShortNumberOfSignificantDigits + 3 + 2; }
|
||||
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
ComplexModel * m_complex;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
return Poincare::Coordinate2D<float>(std::cos(t), std::sin(t));
|
||||
}, nullptr, nullptr, true, Palette::GreyDark, false);
|
||||
// Draw dashed segment to indicate sine and cosine
|
||||
drawSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3);
|
||||
// Draw angle position on the circle
|
||||
drawDot(ctx, rect, c, s, Palette::Red, Size::Large);
|
||||
// Draw graduations
|
||||
|
||||
@@ -12,7 +12,6 @@ public:
|
||||
TrigonometryGraphView(TrigonometryModel * model);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override { return nullptr; }
|
||||
TrigonometryModel * m_model;
|
||||
};
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre
|
||||
singleLine = exactOutputWidth + inputWidth < maxWidth - 40;
|
||||
if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) {
|
||||
KDCoordinate exactOutputBaseline = exactLayout.baseline();
|
||||
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline);
|
||||
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline) + singleMargin;
|
||||
} else {
|
||||
if (allExpressionsInline) {
|
||||
KDCoordinate exactOutputBaseline = exactLayout.baseline();
|
||||
|
||||
@@ -13,12 +13,15 @@ PythonAbs = "Absolute/r Wert/Größe"
|
||||
PythonAcos = "Arkuskosinus"
|
||||
PythonAcosh = "Hyperbelkosinus"
|
||||
PythonAppend = "Hängt x an das Ende der Liste"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arkussinus"
|
||||
PythonAsinh = "Hyperbelsinus"
|
||||
PythonAtan = "Arkustangens"
|
||||
PythonAtan2 = "Gib atan(y/x)"
|
||||
PythonAtanh = "Hyperbeltangens"
|
||||
PythonBin = "Ganzzahl nach binär"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Ganzzahl nach binär konvertieren"
|
||||
PythonCeil = "Aufrundung"
|
||||
PythonChoice = "Zufallszahl aus der Liste"
|
||||
PythonClear = "Leere die Liste"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Rest und Exponent von x"
|
||||
PythonGamma = "Gammafunktion"
|
||||
PythonGetPixel = "Farbe von Pixel (x,y)"
|
||||
PythonGetrandbits = "Ganzzahl mit k zufälligen Bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Ganzzahl zu Hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "cmath Modul importieren"
|
||||
PythonImportIon = "ion Modul importieren"
|
||||
PythonImportKandinsky = "kandinsky Modul importieren"
|
||||
PythonImportRandom = "random Modul importieren"
|
||||
PythonImportMath = "math Modul importieren"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "time Modul importieren"
|
||||
PythonImportTurtle = "turtle Modul importieren"
|
||||
PythonIndex = "Index, bei dem x zuerst vorkommt"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,9 +146,11 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonSin = "Sinus"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
PythonSort = "Sort the list"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Wurzel"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangens"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Valeur absolue/Module"
|
||||
PythonAcos = "Arc cosinus"
|
||||
PythonAcosh = "Arc cosinus hyperbolique"
|
||||
PythonAppend = "Insère x à la fin de la liste"
|
||||
PythonArrow = "Flèche de (x,y) à (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sinus"
|
||||
PythonAsinh = "Arc sinus hyperbolique"
|
||||
PythonAtan = "Arc tangente"
|
||||
PythonAtan2 = "Calcul de atan(y/x)"
|
||||
PythonAtanh = "Arc tangente hyperbolique"
|
||||
PythonAxis = "Met les axes (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Diagramme en barres de la liste x"
|
||||
PythonBin = "Conversion d'un entier en binaire"
|
||||
PythonCeil = "Plafond"
|
||||
PythonChoice = "Nombre aléatoire dans la liste"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantisse et exposant de x : (m,e)"
|
||||
PythonGamma = "Fonction gamma"
|
||||
PythonGetPixel = "Renvoie la couleur du pixel (x,y)"
|
||||
PythonGetrandbits = "Nombre aléatoire sur k bits"
|
||||
PythonGrid = "Affiche ou masque la grille"
|
||||
PythonHex = "Conversion entier en hexadécimal"
|
||||
PythonHist = "Histogramme de la liste x"
|
||||
PythonImportCmath = "Importation du module cmath"
|
||||
PythonImportIon = "Importation du module ion"
|
||||
PythonImportKandinsky = "Importation du module kandinsky"
|
||||
PythonImportRandom = "Importation du module random"
|
||||
PythonImportMath = "Importation du module math"
|
||||
PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot"
|
||||
PythonImportTurtle = "Importation du module turtle"
|
||||
PythonImportTime = "Importation du module time"
|
||||
PythonIndex = "Indice première occurrence de x"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithme de base a"
|
||||
PythonLog10 = "Logarithme décimal"
|
||||
PythonLog2 = "Logarithme de base 2"
|
||||
PythonMathFunction = "Préfixe fonction du module math"
|
||||
PythonMatplotlibPyplotFunction = "Préfixe du module matplotlib.pyplot"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Parties fractionnaire et entière"
|
||||
PythonMonotonic = "Renvoie la valeur de l'horloge"
|
||||
PythonOct = "Conversion en octal"
|
||||
PythonPhase = "Argument de z"
|
||||
PythonPlot = "Trace y en fonction de x"
|
||||
PythonPolar = "Conversion en polaire"
|
||||
PythonPop = "Supprime le dernier élément"
|
||||
PythonPower = "x à la puissance y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "Conversion en algébrique"
|
||||
PythonRemove = "Supprime le premier x de la liste"
|
||||
PythonReverse = "Inverse les éléments de la liste"
|
||||
PythonRound = "Arrondi à n décimales"
|
||||
PythonScatter = "Nuage des points (x,y)"
|
||||
PythonSeed = "Initialiser générateur aléatoire"
|
||||
PythonSetPixel = "Colore le pixel (x,y)"
|
||||
PythonShow = "Affiche la figure"
|
||||
PythonSin = "Sinus"
|
||||
PythonSinh = "Sinus hyperbolique"
|
||||
PythonSleep = "Suspend l'exécution t secondes"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Racine carrée"
|
||||
PythonSum = "Somme des éléments de la liste"
|
||||
PythonTan = "Tangente"
|
||||
PythonTanh = "Tangente hyperbolique"
|
||||
PythonText = "Affiche un texte en (x,y)"
|
||||
PythonTimeFunction = "Préfixe fonction module time"
|
||||
PythonTrunc = "Troncature entière"
|
||||
PythonTurtleBackward = "Recule de x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Abszolút érték / nagyság"
|
||||
PythonAcos = "Arc koszinusz"
|
||||
PythonAcosh = "Íves hiperbolikus koszinusz"
|
||||
PythonAppend = "x hozzáadása a lista végéhez"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc szinusz"
|
||||
PythonAsinh = "Íves hiperbolikus szinusz"
|
||||
PythonAtan = "Arc érintö"
|
||||
PythonAtan2 = "Visszatérés atan (y / x)"
|
||||
PythonAtanh = "Arc hiperbolikus érintö"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Egész szám konvertálása binárisra"
|
||||
PythonCeil = "Mennyezet"
|
||||
PythonChoice = "Véletlenszerü szám a listában"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa és az x exponense"
|
||||
PythonGamma = "Gamma funkció"
|
||||
PythonGetPixel = "Visszatérési pixel (x, y) szín"
|
||||
PythonGetrandbits = "Egész szám k véletlen bittel"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Egész szám konvertálása hexadecimálisra"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "cmath modul importálása"
|
||||
PythonImportIon = "Ion modul importálása"
|
||||
PythonImportKandinsky = "Kandinsky modul importálása"
|
||||
PythonImportRandom = "Véletlenszerü modul importálása"
|
||||
PythonImportMath = "Import matematikai modul"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Idömodul importálása"
|
||||
PythonImportTurtle = "Import teknös modul"
|
||||
PythonIndex = "Az elsö x esemény indexe"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logaritmus az alap"
|
||||
PythonLog10 = "Logaritmus az alaphoz 10"
|
||||
PythonLog2 = "Logaritmus az alaphoz 2"
|
||||
PythonMathFunction = "matematikai modul funkció elötag"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Az x tört és egész részei"
|
||||
PythonMonotonic = "A monoton óra értéke"
|
||||
PythonOct = "Egész szám konvertálása oktális értékre"
|
||||
PythonPhase = "z fázis"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z poláris koordinátákban"
|
||||
PythonPop = "Az utolsó elem eltávolítása és visszaküldése"
|
||||
PythonPower = "x emelve az y teljesítményre"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z derékszögü koordinátákban"
|
||||
PythonRemove = "Távolítsa el az x elsö elöfordulását"
|
||||
PythonReverse = "A lista elemeinek megfordítása"
|
||||
PythonRound = "N számjegyre kerekítve"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Inicializálja a véletlenszám-generátort"
|
||||
PythonSetPixel = "Színes pixel (x, y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hiperbolikus szinusz"
|
||||
PythonSleep = "A végrehajtás felfüggesztése t másodpercre"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Négyzetgyök"
|
||||
PythonSum = "Összegzi a lista elemeit"
|
||||
PythonTan = "Érintö"
|
||||
PythonTanh = "Hiperbolikus érintö"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "idömodul funkció elötag"
|
||||
PythonTrunc = "x egészre csonkítva"
|
||||
PythonTurtleBackward = "Visszalépés x pixelrel"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -12,11 +12,15 @@ PythonCommandAcos = "acos(x)"
|
||||
PythonCommandAcosh = "acosh(x)"
|
||||
PythonCommandAppend = "list.append(x)"
|
||||
PythonCommandAppendWithoutArg = ".append(\x11)"
|
||||
PythonCommandArrow = "arrow(x,y,dx,dy)"
|
||||
PythonCommandAsin = "asin(x)"
|
||||
PythonCommandAsinh = "asinh(x)"
|
||||
PythonCommandAtan = "atan(x)"
|
||||
PythonCommandAtan2 = "atan2(y,x)"
|
||||
PythonCommandAtanh = "atanh(x)"
|
||||
PythonCommandAxis = "axis((xmin,xmax,ymin,ymax))"
|
||||
PythonCommandAxisWithoutArg = "axis(\x11)"
|
||||
PythonCommandBar = "bar(x,height)"
|
||||
PythonCommandBin = "bin(x)"
|
||||
PythonCommandCeil = "ceil(x)"
|
||||
PythonCommandChoice = "choice(list)"
|
||||
@@ -52,13 +56,16 @@ PythonCommandFrExp = "frexp(x)"
|
||||
PythonCommandGamma = "gamma(x)"
|
||||
PythonCommandGetPixel = "get_pixel(x,y)"
|
||||
PythonCommandGetrandbits = "getrandbits(k)"
|
||||
PythonCommandGrid = "grid()"
|
||||
PythonCommandHex = "hex(x)"
|
||||
PythonCommandHist = "hist(x,bins)"
|
||||
PythonCommandImag = "z.imag"
|
||||
PythonCommandImagWithoutArg = ".imag"
|
||||
PythonCommandImportFromCmath = "from cmath import *"
|
||||
PythonCommandImportFromIon = "from ion import *"
|
||||
PythonCommandImportFromKandinsky = "from kandinsky import *"
|
||||
PythonCommandImportFromMath = "from math import *"
|
||||
PythonCommandImportFromMatplotlibPyplot = "from matplotlib.pyplot import *"
|
||||
PythonCommandImportFromRandom = "from random import *"
|
||||
PythonCommandImportFromTime = "from time import *"
|
||||
PythonCommandImportFromTurtle = "from turtle import *"
|
||||
@@ -66,6 +73,7 @@ PythonCommandImportCmath = "import cmath"
|
||||
PythonCommandImportIon = "import ion"
|
||||
PythonCommandImportKandinsky = "import kandinsky"
|
||||
PythonCommandImportMath = "import math"
|
||||
PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot"
|
||||
PythonCommandImportRandom = "import random"
|
||||
PythonCommandImportTime = "import time"
|
||||
PythonCommandImportTurtle = "import turtle"
|
||||
@@ -138,12 +146,15 @@ PythonCommandLog2 = "log2(x)"
|
||||
PythonCommandLogComplex = "log(z,a)"
|
||||
PythonCommandMathFunction = "math.function"
|
||||
PythonCommandMathFunctionWithoutArg = "math.\x11"
|
||||
PythonCommandMatplotlibPyplotFunction = "matplotlib.pyplot.function"
|
||||
PythonCommandMatplotlibPyplotFunctionWithoutArg = "matplotlib.pyplot.\x11"
|
||||
PythonCommandMax = "max(list)"
|
||||
PythonCommandMin = "min(list)"
|
||||
PythonCommandModf = "modf(x)"
|
||||
PythonCommandMonotonic = "monotonic()"
|
||||
PythonCommandOct = "oct(x)"
|
||||
PythonCommandPhase = "phase(z)"
|
||||
PythonCommandPlot = "plot(x,y)"
|
||||
PythonCommandPolar = "polar(z)"
|
||||
PythonCommandPop = "list.pop()"
|
||||
PythonCommandPopWithoutArg = ".pop()"
|
||||
@@ -165,8 +176,10 @@ PythonCommandRemoveWithoutArg = ".remove(\x11)"
|
||||
PythonCommandReverse = "list.reverse()"
|
||||
PythonCommandReverseWithoutArg = ".reverse()"
|
||||
PythonCommandRound = "round(x, n)"
|
||||
PythonCommandScatter = "scatter(x,y)"
|
||||
PythonCommandSeed = "seed(x)"
|
||||
PythonCommandSetPixel = "set_pixel(x,y,color)"
|
||||
PythonCommandShow = "show()"
|
||||
PythonCommandSin = "sin(x)"
|
||||
PythonCommandSinComplex = "sin(z)"
|
||||
PythonCommandSinh = "sinh(x)"
|
||||
@@ -179,6 +192,7 @@ PythonCommandSqrtComplex = "sqrt(z)"
|
||||
PythonCommandSum = "sum(list)"
|
||||
PythonCommandTan = "tan(x)"
|
||||
PythonCommandTanh = "tanh(x)"
|
||||
PythonCommandText = "text(x,y,\"text\")"
|
||||
PythonCommandTimeFunction = "time.function"
|
||||
PythonCommandTimeFunctionWithoutArg = "time.\x11"
|
||||
PythonCommandTrunc = "trunc(x)"
|
||||
|
||||
@@ -34,9 +34,8 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
|
||||
m_selectableTableView(this, this, this, this),
|
||||
m_editCell(this, pythonDelegate, this),
|
||||
m_scriptStore(scriptStore),
|
||||
m_sandboxController(this, this),
|
||||
m_inputRunLoopActive(false),
|
||||
m_preventEdition(false)
|
||||
m_sandboxController(this),
|
||||
m_inputRunLoopActive(false)
|
||||
#if EPSILON_GETOPT
|
||||
, m_locked(lockOnConsole)
|
||||
#endif
|
||||
@@ -82,14 +81,12 @@ void ConsoleController::runAndPrintForCommand(const char * command) {
|
||||
assert(m_outputAccumulationBuffer[0] == '\0');
|
||||
|
||||
// Draw the console before running the code
|
||||
m_preventEdition = true;
|
||||
m_editCell.setText("");
|
||||
m_editCell.setPrompt("");
|
||||
refreshPrintOutput();
|
||||
|
||||
runCode(storedCommand);
|
||||
|
||||
m_preventEdition = false;
|
||||
m_editCell.setPrompt(sStandardPromptText);
|
||||
m_editCell.setEditing(true);
|
||||
|
||||
@@ -108,9 +105,7 @@ const char * ConsoleController::inputText(const char * prompt) {
|
||||
m_inputRunLoopActive = true;
|
||||
|
||||
// Hide the sandbox if it is displayed
|
||||
if (sandboxIsDisplayed()) {
|
||||
hideSandbox();
|
||||
}
|
||||
hideAnyDisplayedViewController();
|
||||
|
||||
const char * promptText = prompt;
|
||||
char * s = const_cast<char *>(prompt);
|
||||
@@ -157,8 +152,7 @@ const char * ConsoleController::inputText(const char * prompt) {
|
||||
m_editCell.clearAndReduceSize();
|
||||
|
||||
// Reload the history
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
reloadData(true);
|
||||
appsContainer->redrawWindow();
|
||||
|
||||
// Launch a new input loop
|
||||
@@ -191,14 +185,21 @@ void ConsoleController::viewWillAppear() {
|
||||
m_importScriptsWhenViewAppears = false;
|
||||
autoImport();
|
||||
}
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
|
||||
reloadData(true);
|
||||
}
|
||||
|
||||
void ConsoleController::didBecomeFirstResponder() {
|
||||
Container::activeApp()->setFirstResponder(&m_editCell);
|
||||
if (!isDisplayingViewController()) {
|
||||
Container::activeApp()->setFirstResponder(&m_editCell);
|
||||
} else {
|
||||
/* A view controller might be displayed: for example, when pushing the
|
||||
* console on the stack controller, we auto-import scripts during the
|
||||
* 'viewWillAppear' and then we set the console as first responder. The
|
||||
* sandbox or the matplotlib controller might have been pushed in the
|
||||
* auto-import. */
|
||||
Container::activeApp()->setFirstResponder(stackViewController()->topViewController());
|
||||
}
|
||||
}
|
||||
|
||||
bool ConsoleController::handleEvent(Ion::Events::Event event) {
|
||||
@@ -347,11 +348,8 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c
|
||||
}
|
||||
telemetryReportEvent("Console", text);
|
||||
runAndPrintForCommand(text);
|
||||
if (!sandboxIsDisplayed()) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_editCell.setEditing(true);
|
||||
textField->setText("");
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
if (!isDisplayingViewController()) {
|
||||
reloadData(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -378,37 +376,53 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConsoleController::displaySandbox() {
|
||||
if (sandboxIsDisplayed()) {
|
||||
return;
|
||||
}
|
||||
stackViewController()->push(&m_sandboxController);
|
||||
}
|
||||
|
||||
void ConsoleController::hideSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
return;
|
||||
}
|
||||
m_sandboxController.hide();
|
||||
}
|
||||
|
||||
void ConsoleController::resetSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
if (stackViewController()->topViewController() != sandbox()) {
|
||||
return;
|
||||
}
|
||||
m_sandboxController.reset();
|
||||
}
|
||||
|
||||
void ConsoleController::refreshPrintOutput() {
|
||||
if (sandboxIsDisplayed()) {
|
||||
void ConsoleController::displayViewController(ViewController * controller) {
|
||||
if (stackViewController()->topViewController() == controller) {
|
||||
return;
|
||||
}
|
||||
hideAnyDisplayedViewController();
|
||||
stackViewController()->push(controller);
|
||||
}
|
||||
|
||||
void ConsoleController::hideAnyDisplayedViewController() {
|
||||
if (!isDisplayingViewController()) {
|
||||
return;
|
||||
}
|
||||
stackViewController()->pop();
|
||||
}
|
||||
|
||||
bool ConsoleController::isDisplayingViewController() {
|
||||
/* The StackViewController model state is the best way to know wether the
|
||||
* console is displaying a View Controller (Sandbox or Matplotlib). Indeed,
|
||||
* keeping a boolean or a pointer raises the issue of when updating it - when
|
||||
* 'viewWillAppear' or when 'didEnterResponderChain' - in both cases, the
|
||||
* state would be wrong at some point... */
|
||||
return stackViewController()->depth() > 2;
|
||||
}
|
||||
|
||||
void ConsoleController::refreshPrintOutput() {
|
||||
if (!isDisplayingViewController()) {
|
||||
reloadData(false);
|
||||
AppsContainer::sharedAppsContainer()->redrawWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleController::reloadData(bool isEditing) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
if (m_preventEdition) {
|
||||
if (isEditing) {
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
} else {
|
||||
m_editCell.setEditing(false);
|
||||
}
|
||||
AppsContainer::sharedAppsContainer()->redrawWindow();
|
||||
}
|
||||
|
||||
/* printText is called by the Python machine.
|
||||
@@ -457,12 +471,11 @@ void ConsoleController::printText(const char * text, size_t length) {
|
||||
}
|
||||
|
||||
void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
if (sandboxIsDisplayed()) {
|
||||
/* The sandbox might be displayed, for instance if we are auto-importing
|
||||
* several scripts that draw at importation. In this case, we want to remove
|
||||
* the sandbox. */
|
||||
hideSandbox();
|
||||
}
|
||||
/* The sandbox might be displayed, for instance if we are auto-importing
|
||||
* several scripts that draw at importation. In this case, we want to remove
|
||||
* the sandbox. */
|
||||
hideAnyDisplayedViewController();
|
||||
|
||||
if (script.importationStatus() || force) {
|
||||
// Step 1 - Create the command "from scriptName import *".
|
||||
|
||||
@@ -488,11 +501,8 @@ void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
// Step 2 - Run the command
|
||||
runAndPrintForCommand(command);
|
||||
}
|
||||
if (!sandboxIsDisplayed() && force) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
if (!isDisplayingViewController() && force) {
|
||||
reloadData(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,10 @@ public:
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
|
||||
// MicroPython::ExecutionEnvironment
|
||||
void displaySandbox() override;
|
||||
void hideSandbox() override;
|
||||
ViewController * sandbox() override { return &m_sandboxController; }
|
||||
void resetSandbox() override;
|
||||
void displayViewController(ViewController * controller) override;
|
||||
void hideAnyDisplayedViewController() override;
|
||||
void refreshPrintOutput() override;
|
||||
void printText(const char * text, size_t length) override;
|
||||
const char * inputText(const char * prompt) override;
|
||||
@@ -82,6 +83,8 @@ private:
|
||||
static constexpr int k_numberOfLineCells = (Ion::Display::Height - Metric::TitleBarHeight) / 14 + 2; // 14 = KDFont::SmallFont->glyphSize().height()
|
||||
// k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells.
|
||||
static constexpr int k_outputAccumulationBufferSize = 100;
|
||||
bool isDisplayingViewController();
|
||||
void reloadData(bool isEditing);
|
||||
void flushOutputAccumulationBufferToStore();
|
||||
void appendTextToOutputAccumulationBuffer(const char * text, size_t length);
|
||||
void emptyOutputAccumulationBuffer();
|
||||
@@ -103,7 +106,6 @@ private:
|
||||
SandboxController m_sandboxController;
|
||||
bool m_inputRunLoopActive;
|
||||
bool m_autoImportScripts;
|
||||
bool m_preventEdition;
|
||||
#if EPSILON_GETOPT
|
||||
bool m_locked;
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
namespace Code {
|
||||
|
||||
static inline int minInt(int x, int y) { return x < y ? x : y; }
|
||||
|
||||
ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) :
|
||||
HighlightCell(),
|
||||
Responder(parentResponder),
|
||||
@@ -65,9 +67,12 @@ void ConsoleEditCell::clearAndReduceSize() {
|
||||
const char * ConsoleEditCell::shiftCurrentTextAndClear() {
|
||||
size_t previousBufferSize = m_textField.draftTextBufferSize();
|
||||
m_textField.setDraftTextBufferSize(previousBufferSize + 1);
|
||||
char * textFieldBuffer = m_textField.draftTextBuffer();
|
||||
char * textFieldBuffer = const_cast<char *>(m_textField.text());
|
||||
char * newTextPosition = textFieldBuffer + 1;
|
||||
strlcpy(newTextPosition, textFieldBuffer, previousBufferSize);
|
||||
assert(previousBufferSize > 0);
|
||||
size_t copyLength = minInt(previousBufferSize - 1, strlen(textFieldBuffer));
|
||||
memmove(newTextPosition, textFieldBuffer, copyLength);
|
||||
newTextPosition[copyLength] = 0;
|
||||
textFieldBuffer[0] = 0;
|
||||
return newTextPosition;
|
||||
}
|
||||
|
||||
@@ -92,30 +92,6 @@ const ToolboxMessageTree MathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLgamma, I18n::Message::PythonLgamma)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree KandinskyModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree RandomModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree CMathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromCmath, I18n::Message::PythonImportCmath, false),
|
||||
@@ -132,6 +108,21 @@ const ToolboxMessageTree CMathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinComplex, I18n::Message::PythonSin)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree TurtleModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
@@ -167,6 +158,30 @@ const ToolboxMessageTree TurtleModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree RandomModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree KandinskyModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree IonModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
|
||||
@@ -231,8 +246,9 @@ const ToolboxMessageTree TimeModuleChildren[] = {
|
||||
const ToolboxMessageTree modulesChildren[] = {
|
||||
ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::IonModule, IonModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::TimeModule, TimeModuleChildren)
|
||||
@@ -251,12 +267,15 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAbs, I18n::Message::PythonAbs),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcos, I18n::Message::PythonAcos),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcosh, I18n::Message::PythonAcosh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan2, I18n::Message::PythonAtan2),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtanh, I18n::Message::PythonAtanh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false),
|
||||
@@ -290,6 +309,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMath, I18n::Message::PythonImportMath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportTime, false),
|
||||
@@ -299,13 +319,16 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false),
|
||||
@@ -335,6 +358,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog10, I18n::Message::PythonLog10),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog2, I18n::Message::PythonLog2),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMathFunction, I18n::Message::PythonMathFunction, false, I18n::Message::PythonCommandMathFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMax, I18n::Message::PythonMax),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMin, I18n::Message::PythonMin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf),
|
||||
@@ -350,6 +374,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians),
|
||||
@@ -364,9 +389,11 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSin, I18n::Message::PythonSin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinh, I18n::Message::PythonSinh),
|
||||
@@ -377,6 +404,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSum, I18n::Message::PythonSum),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTan, I18n::Message::PythonTan),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTanh, I18n::Message::PythonTanh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, false, I18n::Message::PythonCommandTimeFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include "sandbox_controller.h"
|
||||
#include <apps/apps_container.h>
|
||||
|
||||
extern "C" {
|
||||
#include <python/port/mod/turtle/modturtle.h>
|
||||
}
|
||||
|
||||
namespace Code {
|
||||
|
||||
SandboxController::SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment) :
|
||||
SandboxController::SandboxController(Responder * parentResponder) :
|
||||
ViewController(parentResponder),
|
||||
m_solidColorView(Palette::CodeBackground),
|
||||
m_executionEnvironment(executionEnvironment)
|
||||
m_solidColorView(Palette::CodeBackground)
|
||||
{
|
||||
assert(executionEnvironment != nullptr);
|
||||
}
|
||||
|
||||
StackViewController * SandboxController::stackViewController() {
|
||||
@@ -20,19 +22,12 @@ void SandboxController::reset() {
|
||||
redrawWindow();
|
||||
}
|
||||
|
||||
void SandboxController::hide() {
|
||||
stackViewController()->pop();
|
||||
}
|
||||
|
||||
void SandboxController::viewWillAppear() {
|
||||
assert(m_executionEnvironment != nullptr);
|
||||
m_executionEnvironment->setSandboxIsDisplayed(true);
|
||||
redrawWindow();
|
||||
}
|
||||
|
||||
void SandboxController::viewDidDisappear() {
|
||||
assert(m_executionEnvironment != nullptr);
|
||||
m_executionEnvironment->setSandboxIsDisplayed(false);
|
||||
modturtle_view_did_disappear();
|
||||
}
|
||||
|
||||
bool SandboxController::handleEvent(Ion::Events::Event event) {
|
||||
|
||||
@@ -11,10 +11,9 @@ namespace Code {
|
||||
|
||||
class SandboxController : public ViewController {
|
||||
public:
|
||||
SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment);
|
||||
SandboxController(Responder * parentResponder);
|
||||
StackViewController * stackViewController();
|
||||
void reset();
|
||||
void hide();
|
||||
|
||||
// ViewController
|
||||
View * view() override { return &m_solidColorView; }
|
||||
@@ -26,7 +25,6 @@ public:
|
||||
private:
|
||||
void redrawWindow();
|
||||
SolidColorView m_solidColorView;
|
||||
MicroPython::ExecutionEnvironment * m_executionEnvironment;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
|
||||
ScriptStore::ScriptStore()
|
||||
{
|
||||
addScriptFromTemplate(ScriptTemplate::Squares());
|
||||
addScriptFromTemplate(ScriptTemplate::Parabola());
|
||||
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
|
||||
addScriptFromTemplate(ScriptTemplate::Polynomial());
|
||||
}
|
||||
|
||||
@@ -53,6 +53,37 @@ def roots(a,b,c):
|
||||
else:
|
||||
return None)");
|
||||
|
||||
constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import *
|
||||
from math import *
|
||||
|
||||
g=9.81
|
||||
|
||||
def x(t,v_0,alpha):
|
||||
return v_0*cos(alpha)*t
|
||||
def y(t,v_0,alpha,h_0):
|
||||
return -0.5*g*t**2+v_0*sin(alpha)*t+h_0
|
||||
|
||||
def vx(v_0,alpha):
|
||||
return v_0*cos(alpha)
|
||||
def vy(t,v_0,alpha):
|
||||
return -g*t+v_0*sin(alpha)
|
||||
|
||||
def t_max(v_0,alpha,h_0):
|
||||
return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g
|
||||
|
||||
def simulation(v_0=15,alpha=pi/4,h_0=2):
|
||||
tMax=t_max(v_0,alpha,h_0)
|
||||
accuracy=1/10**(floor(log10(tMax))-1)
|
||||
T_MAX=floor(tMax*accuracy)+1
|
||||
X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]
|
||||
Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]
|
||||
VX=[vx(v_0,alpha) for t in range(T_MAX)]
|
||||
VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]
|
||||
for i in range(T_MAX):
|
||||
arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)
|
||||
grid()
|
||||
show())");
|
||||
|
||||
const ScriptTemplate * ScriptTemplate::Empty() {
|
||||
return &emptyScriptTemplate;
|
||||
}
|
||||
@@ -69,4 +100,8 @@ const ScriptTemplate * ScriptTemplate::Polynomial() {
|
||||
return &polynomialScriptTemplate;
|
||||
}
|
||||
|
||||
const ScriptTemplate * ScriptTemplate::Parabola() {
|
||||
return ¶bolaScriptTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public:
|
||||
static const ScriptTemplate * Squares();
|
||||
static const ScriptTemplate * Mandelbrot();
|
||||
static const ScriptTemplate * Polynomial();
|
||||
static const ScriptTemplate * Parabola();
|
||||
const char * name() const { return m_name; }
|
||||
const char * content() const { return m_value+1; }
|
||||
const char * value() const { return m_value; }
|
||||
|
||||
@@ -2,6 +2,7 @@ CmathModule = "cmath"
|
||||
IonModule = "ion"
|
||||
KandinskyModule = "kandinsky"
|
||||
MathModule = "math"
|
||||
MatplotlibPyplotModule = "matplotlib.pyplot"
|
||||
TimeModule = "time"
|
||||
TurtleModule = "turtle"
|
||||
ForLoopMenu = "For"
|
||||
|
||||
@@ -58,7 +58,7 @@ App::App(Snapshot * snapshot) :
|
||||
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey),
|
||||
m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController),
|
||||
m_listStackViewController(&m_tabViewController, &m_listHeader),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
|
||||
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
|
||||
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
|
||||
m_graphStackViewController(&m_tabViewController, &m_graphHeader),
|
||||
|
||||
@@ -30,7 +30,6 @@ protected:
|
||||
MessageTextView m_defaultBannerView;
|
||||
bool m_isActive;
|
||||
private:
|
||||
bool handleZoom(Ion::Events::Event event) override { return false; }
|
||||
bool handleEnter() override;
|
||||
bool moveCursorHorizontally(int direction, bool fast = false) override;
|
||||
Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; }
|
||||
|
||||
@@ -11,8 +11,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; }
|
||||
static inline double minDouble(double x, double y) { return x < y ? x : y; }
|
||||
static inline double maxDouble(double x, double y) { return x > y ? x : y; }
|
||||
|
||||
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
|
||||
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion),
|
||||
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
|
||||
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion),
|
||||
m_bannerView(this, inputEventHandlerDelegate, this),
|
||||
m_view(curveViewRange, m_cursor, &m_bannerView, &m_cursorView),
|
||||
m_graphRange(curveViewRange),
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Graph {
|
||||
|
||||
class GraphController : public Shared::FunctionGraphController, public GraphControllerHelper {
|
||||
public:
|
||||
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
|
||||
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
|
||||
I18n::Message emptyMessage() override;
|
||||
void viewWillAppear() override;
|
||||
bool displayDerivativeInBanner() const { return m_displayDerivativeInBanner; }
|
||||
|
||||
@@ -60,13 +60,12 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
}, f.operator->(), context(), f->color(), true, record == m_selectedRecord, m_highlightedStart, m_highlightedEnd);
|
||||
/* Draw tangent */
|
||||
if (m_tangent && record == m_selectedRecord) {
|
||||
float tangentParameter[2];
|
||||
tangentParameter[0] = f->approximateDerivative(m_curveViewCursor->x(), context());
|
||||
tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2();
|
||||
drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float t, void * model, void * context) {
|
||||
float * tangent = (float *)model;
|
||||
return Poincare::Coordinate2D<float>(t, tangent[0]*t+tangent[1]);
|
||||
}, tangentParameter, nullptr, Palette::GraphTangent);
|
||||
float tangentParameterA = f->approximateDerivative(m_curveViewCursor->x(), context());
|
||||
float tangentParameterB = -tangentParameterA*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2();
|
||||
// To represent the tangent, we draw segment from and to abscissas at the extremity of the drawn rect
|
||||
float minAbscissa = pixelToFloat(Axis::Horizontal, rect.left());
|
||||
float maxAbscissa = pixelToFloat(Axis::Horizontal, rect.right());
|
||||
drawSegment(ctx, rect, minAbscissa, tangentParameterA*minAbscissa+tangentParameterB, maxAbscissa, tangentParameterA*maxAbscissa+tangentParameterB, Palette::GraphTangent, false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -25,9 +25,12 @@ double Distribution::rightIntegralFromAbscissa(double x) const {
|
||||
}
|
||||
|
||||
double Distribution::finiteIntegralBetweenAbscissas(double a, double b) const {
|
||||
if (b <= a) {
|
||||
if (b < a) {
|
||||
return 0.0;
|
||||
}
|
||||
if (a == b) {
|
||||
return evaluateAtDiscreteAbscissa(a);
|
||||
}
|
||||
if (isContinuous()) {
|
||||
return cumulativeDistributiveFunctionAtAbscissa(b) - cumulativeDistributiveFunctionAtAbscissa(a);
|
||||
}
|
||||
@@ -100,6 +103,7 @@ double Distribution::rightIntegralInverseForProbability(double * probability) {
|
||||
}
|
||||
|
||||
double Distribution::evaluateAtDiscreteAbscissa(int k) const {
|
||||
assert(isContinuous()); // Discrete distributions override this method
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,13 @@ void assert_cumulative_distributive_function_direct_and_inverse_is(Probability::
|
||||
quiz_assert(!std::isnan(r));
|
||||
quiz_assert(!std::isinf(r));
|
||||
quiz_assert(std::fabs(r-x) < FLT_EPSILON || std::fabs(r-x)/x < FLT_EPSILON);
|
||||
}
|
||||
|
||||
void assert_finite_integral_between_abscissas_is(Probability::Distribution * distribution, double a, double b, double result) {
|
||||
double r = distribution->finiteIntegralBetweenAbscissas(a, b);
|
||||
quiz_assert(!std::isnan(r));
|
||||
quiz_assert(!std::isinf(r));
|
||||
quiz_assert(std::fabs(r-result) < FLT_EPSILON || std::fabs(r-result)/result < FLT_EPSILON);
|
||||
}
|
||||
|
||||
//TODO other distributions
|
||||
@@ -37,6 +43,13 @@ QUIZ_CASE(binomial_distribution) {
|
||||
distribution.setParameterAtIndex(0.1, 1);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 0.0, 0.166771816996665822596668249389040283858776092529296875);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.0, 0.4817852491014791294077213024138472974300384521484375);
|
||||
|
||||
// B(21, 0.2)
|
||||
distribution.setParameterAtIndex(21.0, 0);
|
||||
distribution.setParameterAtIndex(0.2, 1);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.21563235015849934848);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.398919847793223794688);
|
||||
}
|
||||
|
||||
QUIZ_CASE(chi_squared_distribution) {
|
||||
@@ -58,6 +71,12 @@ QUIZ_CASE(chi_squared_distribution) {
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.047059684573231390369851823152202996425330638885498046875);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.250530060451470470983537097708904184401035308837890625);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 4.987, 0.53051693435084168459781039928202517330646514892578125);
|
||||
|
||||
// Chi Squared distribution with 6 degrees of freedom
|
||||
distribution.setParameterAtIndex(6.0, 0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.1328633002997339414718);
|
||||
}
|
||||
|
||||
QUIZ_CASE(student_distribution) {
|
||||
@@ -79,6 +98,12 @@ QUIZ_CASE(student_distribution) {
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, -4.987, 0.00167496657737900025118837898929768925881944596767425537109375);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.876837383157582639370275501278229057788848876953125);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.98612148076325445433809591122553683817386627197265625);
|
||||
|
||||
// Student distribution with 6 degrees of freedom
|
||||
distribution.setParameterAtIndex(6.0, 0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.002333318101494775250);
|
||||
}
|
||||
|
||||
QUIZ_CASE(geometric_distribution) {
|
||||
@@ -92,6 +117,12 @@ QUIZ_CASE(geometric_distribution) {
|
||||
distribution.setParameterAtIndex(0.2, 0);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 7.0, 0.8322278399999998299563230830244719982147216796875);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 3.0, 0.5904);
|
||||
|
||||
// Geometric distribution with probability of success 0.4
|
||||
distribution.setParameterAtIndex(0.4, 0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.24);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.384);
|
||||
}
|
||||
|
||||
QUIZ_CASE(fisher_distribution) {
|
||||
@@ -115,4 +146,10 @@ QUIZ_CASE(fisher_distribution) {
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.4, 0.94560850441205857);
|
||||
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.425, 0.95425004959692871775);
|
||||
|
||||
// Fisher distribution with d1 = 4 and d2 = 2
|
||||
distribution.setParameterAtIndex(4.0, 0);
|
||||
distribution.setParameterAtIndex(2.0, 1);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0);
|
||||
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.19555555555555555);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ App * App::Snapshot::unpack(Container * container) {
|
||||
}
|
||||
|
||||
void App::Snapshot::reset() {
|
||||
m_store.deleteAllPairs();
|
||||
m_store.reset();
|
||||
m_modelVersion = 0;
|
||||
m_rangeVersion = 0;
|
||||
setActiveTab(0);
|
||||
@@ -59,7 +59,7 @@ App::App(Snapshot * snapshot, Poincare::Context * parentContext) :
|
||||
m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()),
|
||||
m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController),
|
||||
m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()),
|
||||
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
|
||||
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
|
||||
m_graphStackViewController(&m_tabViewController, &m_graphHeader),
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; }
|
||||
int * selectedSeriesIndex() { return &m_selectedSeriesIndex; }
|
||||
uint32_t * modelVersion() { return &m_modelVersion; }
|
||||
uint32_t * previousModelsVersions() { return m_store.seriesChecksum(); }
|
||||
uint32_t * rangeVersion() { return &m_rangeVersion; }
|
||||
private:
|
||||
void tidy() override;
|
||||
|
||||
@@ -168,6 +168,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
myCell->setFirstText(buffer);
|
||||
buffer[0] = 'Y';
|
||||
myCell->setSecondText(buffer);
|
||||
assert(seriesNumber < Palette::numberOfDataColors());
|
||||
myCell->setColor(Palette::DataColor[seriesNumber]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ static inline int maxInt(int x, int y) { return x > y ? x : y; }
|
||||
|
||||
namespace Regression {
|
||||
|
||||
GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) :
|
||||
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, rangeVersion),
|
||||
GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) :
|
||||
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, previousModelsVersions, rangeVersion),
|
||||
m_crossCursorView(),
|
||||
m_roundCursorView(),
|
||||
m_bannerView(this, inputEventHandlerDelegate, this),
|
||||
@@ -351,6 +351,11 @@ uint32_t GraphController::modelVersion() {
|
||||
return m_store->storeChecksum();
|
||||
}
|
||||
|
||||
uint32_t GraphController::modelVersionAtIndex(size_t i) {
|
||||
assert(i < numberOfMemoizedVersions());
|
||||
return *(m_store->seriesChecksum() + i);
|
||||
}
|
||||
|
||||
uint32_t GraphController::rangeVersion() {
|
||||
return m_store->rangeChecksum();
|
||||
}
|
||||
@@ -402,6 +407,7 @@ void GraphController::setRoundCrossCursorView() {
|
||||
bool round = *m_selectedDotIndex < 0;
|
||||
if (round) {
|
||||
// Set the color although the cursor view stays round
|
||||
assert(*m_selectedSeriesIndex < Palette::numberOfDataColors());
|
||||
m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]);
|
||||
}
|
||||
CursorView * nextCursorView = round ? static_cast<Shared::CursorView *>(&m_roundCursorView) : static_cast<Shared::CursorView *>(&m_crossCursorView);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Regression {
|
||||
class GraphController : public Shared::InteractiveCurveViewController {
|
||||
|
||||
public:
|
||||
GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex);
|
||||
GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex);
|
||||
ViewController * initialisationParameterController() override;
|
||||
bool isEmpty() const override;
|
||||
I18n::Message emptyMessage() override;
|
||||
@@ -43,7 +43,9 @@ private:
|
||||
// InteractiveCurveViewController
|
||||
void initCursorParameters() override;
|
||||
uint32_t modelVersion() override;
|
||||
uint32_t modelVersionAtIndex(size_t i) override;
|
||||
uint32_t rangeVersion() override;
|
||||
size_t numberOfMemoizedVersions() const override { return Store::k_numberOfSeries; }
|
||||
int selectedCurveIndex() const override { return *m_selectedSeriesIndex; }
|
||||
bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override;
|
||||
Poincare::Coordinate2D<double> xyValues(int curveIndex, double x, Poincare::Context * context) const override;
|
||||
|
||||
@@ -9,10 +9,8 @@ using namespace Shared;
|
||||
namespace Regression {
|
||||
|
||||
GraphView::GraphView(Store * store, CurveViewCursor * cursor, BannerView * bannerView, Shared::CursorView * cursorView) :
|
||||
CurveView(store, cursor, bannerView, cursorView),
|
||||
m_store(store),
|
||||
m_xLabels{},
|
||||
m_yLabels{}
|
||||
LabeledCurveView(store, cursor, bannerView, cursorView),
|
||||
m_store(store)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,6 +22,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
Poincare::Context * globContext = AppsContainer::sharedAppsContainer()->globalContext();
|
||||
for (int series = 0; series < Store::k_numberOfSeries; series++) {
|
||||
if (!m_store->seriesIsEmpty(series)) {
|
||||
assert(series < Palette::numberOfDataColors());
|
||||
KDColor color = Palette::DataColor[series];
|
||||
Model * seriesModel = m_store->modelForSeries(series);
|
||||
drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float abscissa, void * model, void * context) {
|
||||
@@ -41,13 +40,4 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
}
|
||||
}
|
||||
|
||||
char * GraphView::label(Axis axis, int index) const {
|
||||
if (axis == Axis::Vertical) {
|
||||
assert(index < k_maxNumberOfXLabels);
|
||||
return (char *)m_yLabels[index];
|
||||
}
|
||||
assert(index < k_maxNumberOfYLabels);
|
||||
return (char *)m_xLabels[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,19 +3,16 @@
|
||||
|
||||
#include "store.h"
|
||||
#include "../constant.h"
|
||||
#include "../shared/curve_view.h"
|
||||
#include "../shared/labeled_curve_view.h"
|
||||
|
||||
namespace Regression {
|
||||
|
||||
class GraphView : public Shared::CurveView {
|
||||
class GraphView : public Shared::LabeledCurveView {
|
||||
public:
|
||||
GraphView(Store * store, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
Store * m_store;
|
||||
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,14 @@ static_assert(Store::k_numberOfSeries == 3, "Number of series changed, Regressio
|
||||
Store::Store() :
|
||||
InteractiveCurveViewRange(),
|
||||
DoublePairStore(),
|
||||
m_seriesChecksum{0, 0, 0},
|
||||
m_angleUnit(Poincare::Preferences::AngleUnit::Degree)
|
||||
{
|
||||
for (int i = 0; i < k_numberOfSeries; i++) {
|
||||
m_regressionTypes[i] = Model::Type::Linear;
|
||||
m_regressionChanged[i] = false;
|
||||
}
|
||||
resetMemoization();
|
||||
}
|
||||
|
||||
void Store::reset() {
|
||||
deleteAllPairs();
|
||||
resetMemoization();
|
||||
}
|
||||
|
||||
void Store::tidy() {
|
||||
@@ -188,6 +189,13 @@ double Store::doubleCastedNumberOfPairsOfSeries(int series) const {
|
||||
return DoublePairStore::numberOfPairsOfSeries(series);
|
||||
}
|
||||
|
||||
void Store::resetMemoization() {
|
||||
assert(((int)Model::Type::Linear) == 0);
|
||||
memset(m_seriesChecksum, 0, sizeof(m_seriesChecksum));
|
||||
memset(m_regressionTypes, 0, sizeof(m_regressionTypes));
|
||||
memset(m_regressionChanged, 0, sizeof(m_regressionChanged));
|
||||
}
|
||||
|
||||
float Store::maxValueOfColumn(int series, int i) const {
|
||||
float maxColumn = -FLT_MAX;
|
||||
for (int k = 0; k < numberOfPairsOfSeries(series); k++) {
|
||||
|
||||
@@ -22,6 +22,7 @@ class Store : public Shared::InteractiveCurveViewRange, public Shared::DoublePai
|
||||
public:
|
||||
Store();
|
||||
|
||||
void reset();
|
||||
// Clean pool
|
||||
void tidy();
|
||||
|
||||
@@ -35,6 +36,7 @@ public:
|
||||
assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels);
|
||||
return regressionModel((int)m_regressionTypes[series]);
|
||||
}
|
||||
uint32_t * seriesChecksum() { return m_seriesChecksum; }
|
||||
|
||||
// Dots
|
||||
/* Return the closest dot to abscissa x above the regression curve if
|
||||
@@ -70,6 +72,7 @@ public:
|
||||
double squaredCorrelationCoefficient(int series) const;
|
||||
private:
|
||||
constexpr static float k_displayHorizontalMarginRatio = 0.05f;
|
||||
void resetMemoization();
|
||||
float maxValueOfColumn(int series, int i) const; //TODO LEA why float ?
|
||||
float minValueOfColumn(int series, int i) const; //TODO LEA why float ?
|
||||
Model * regressionModel(int index);
|
||||
|
||||
@@ -55,7 +55,7 @@ App::App(Snapshot * snapshot) :
|
||||
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey),
|
||||
m_listHeader(nullptr, &m_listFooter, &m_listController),
|
||||
m_listStackViewController(&m_tabViewController, &m_listHeader),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
|
||||
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
|
||||
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
|
||||
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
|
||||
m_graphStackViewController(&m_tabViewController, &m_graphHeader),
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Sequence {
|
||||
static inline int minInt(int x, int y) { return (x < y ? x : y); }
|
||||
static inline int maxInt(int x, int y) { return (x > y ? x : y); }
|
||||
|
||||
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
|
||||
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion),
|
||||
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
|
||||
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion),
|
||||
m_bannerView(this, inputEventHandlerDelegate, this),
|
||||
m_view(sequenceStore, graphRange, m_cursor, &m_bannerView, &m_cursorView),
|
||||
m_graphRange(graphRange),
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Sequence {
|
||||
|
||||
class GraphController final : public Shared::FunctionGraphController {
|
||||
public:
|
||||
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
|
||||
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
|
||||
I18n::Message emptyMessage() override;
|
||||
void viewWillAppear() override;
|
||||
TermSumController * termSumController() { return &m_termSumController; }
|
||||
|
||||
@@ -32,9 +32,9 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
if (x >= m_highlightedStart && x <= m_highlightedEnd && record == m_selectedRecord) {
|
||||
KDColor color = m_shouldColorHighlighted ? s->color() : Palette::PrimaryText;
|
||||
if (y >= 0.0f) {
|
||||
drawSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1);
|
||||
} else {
|
||||
drawSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ void Sequence::tidy() {
|
||||
m_firstInitialCondition.tidyName();
|
||||
m_secondInitialCondition.tidy();
|
||||
m_secondInitialCondition.tidyName();
|
||||
m_nameLayout = Layout();
|
||||
}
|
||||
|
||||
Sequence::Type Sequence::type() const {
|
||||
@@ -81,13 +80,10 @@ void Sequence::setInitialRank(int rank) {
|
||||
}
|
||||
|
||||
Poincare::Layout Sequence::nameLayout() {
|
||||
if (m_nameLayout.isUninitialized()) {
|
||||
m_nameLayout = HorizontalLayout::Builder(
|
||||
CodePointLayout::Builder(fullName()[0], KDFont::SmallFont),
|
||||
VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript)
|
||||
);
|
||||
}
|
||||
return m_nameLayout;
|
||||
return HorizontalLayout::Builder(
|
||||
CodePointLayout::Builder(fullName()[0], KDFont::SmallFont),
|
||||
VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript)
|
||||
);
|
||||
}
|
||||
|
||||
bool Sequence::isDefined() {
|
||||
|
||||
@@ -24,8 +24,9 @@ public:
|
||||
DoubleRecurrence = 2
|
||||
};
|
||||
Sequence(Ion::Storage::Record record = Record()) :
|
||||
Function(record),
|
||||
m_nameLayout() {}
|
||||
Function(record)
|
||||
{
|
||||
}
|
||||
I18n::Message parameterMessageName() const override;
|
||||
CodePoint symbol() const override { return 'n'; }
|
||||
void tidy() override;
|
||||
@@ -111,7 +112,7 @@ private:
|
||||
public:
|
||||
SequenceModel() : Shared::ExpressionModel(), m_name() {}
|
||||
void tidyName() { m_name = Poincare::Layout(); }
|
||||
virtual Poincare::Layout name(Sequence * sequence);
|
||||
Poincare::Layout name(Sequence * sequence);
|
||||
protected:
|
||||
virtual void buildName(Sequence * sequence) = 0;
|
||||
Poincare::Layout m_name;
|
||||
@@ -153,7 +154,6 @@ private:
|
||||
DefinitionModel m_definition;
|
||||
FirstInitialConditionModel m_firstInitialCondition;
|
||||
SecondInitialConditionModel m_secondInitialCondition;
|
||||
Poincare::Layout m_nameLayout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() {
|
||||
const char * name = firstAvailableName(&nameIndex);
|
||||
assert(name);
|
||||
// Choose the corresponding color
|
||||
assert(nameIndex < Palette::numberOfDataColors());
|
||||
KDColor color = Palette::DataColor[nameIndex];
|
||||
Sequence::RecordDataBuffer data(color);
|
||||
// m_sequences
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
app_shared_test_src = $(addprefix apps/shared/,\
|
||||
continuous_function.cpp\
|
||||
curve_view_range.cpp \
|
||||
curve_view.cpp \
|
||||
dots.cpp \
|
||||
double_pair_store.cpp \
|
||||
expression_model.cpp \
|
||||
expression_model_handle.cpp \
|
||||
@@ -9,8 +11,11 @@ app_shared_test_src = $(addprefix apps/shared/,\
|
||||
global_context.cpp \
|
||||
interactive_curve_view_range_delegate.cpp \
|
||||
interactive_curve_view_range.cpp \
|
||||
labeled_curve_view.cpp \
|
||||
memoized_curve_view_range.cpp \
|
||||
range_1D.cpp \
|
||||
zoom_and_pan_curve_view_controller.cpp \
|
||||
zoom_curve_view_controller.cpp \
|
||||
)
|
||||
|
||||
app_shared_src = $(addprefix apps/shared/,\
|
||||
@@ -18,9 +23,7 @@ app_shared_src = $(addprefix apps/shared/,\
|
||||
buffer_function_title_cell.cpp \
|
||||
buffer_text_view_with_text_field.cpp \
|
||||
button_with_separator.cpp \
|
||||
dots.cpp \
|
||||
cursor_view.cpp \
|
||||
curve_view.cpp \
|
||||
curve_view_cursor.cpp \
|
||||
editable_cell_table_view_controller.cpp \
|
||||
expression_field_delegate_app.cpp \
|
||||
|
||||
@@ -57,8 +57,7 @@ ContinuousFunction ContinuousFunction::NewModel(Ion::Storage::Record::ErrorStatu
|
||||
static int s_colorIndex = 0;
|
||||
// Create the record
|
||||
char nameBuffer[SymbolAbstract::k_maxNameSize];
|
||||
int numberOfColors = sizeof(Palette::DataColor)/sizeof(KDColor);
|
||||
RecordDataBuffer data(Palette::DataColor[s_colorIndex++ % numberOfColors]);
|
||||
RecordDataBuffer data(Palette::nextDataColor(&s_colorIndex));
|
||||
if (baseName == nullptr) {
|
||||
DefaultName(nameBuffer, SymbolAbstract::k_maxNameSize);
|
||||
baseName = nameBuffer;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef SHARED_CURSOR_VIEW_H
|
||||
#define SHARED_CURSOR_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
#include <escher/transparent_view.h>
|
||||
#include <escher/palette.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class CursorView : public View {
|
||||
class CursorView : public TransparentView {
|
||||
public:
|
||||
virtual void setCursorFrame(KDRect frame, bool force) { View::setFrame(frame, force); }
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
|
||||
@@ -106,11 +106,11 @@ void CurveView::setOkView(View * okView) {
|
||||
* m_frame.height() - 1 yMin()
|
||||
*/
|
||||
|
||||
const float CurveView::pixelWidth() const {
|
||||
float CurveView::pixelWidth() const {
|
||||
return (m_curveViewRange->xMax() - m_curveViewRange->xMin()) / (m_frame.width() - 1);
|
||||
}
|
||||
|
||||
const float CurveView::pixelHeight() const {
|
||||
float CurveView::pixelHeight() const {
|
||||
return (m_curveViewRange->yMax() - m_curveViewRange->yMin()) / (m_frame.height() - 1);
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ void CurveView::drawLabelsAndGraduations(KDContext * ctx, KDRect rect, Axis axis
|
||||
position = positionLabel(horizontalCoordinate, labelPosition, textSize, RelativePosition::Before, RelativePosition::None);
|
||||
if (floatingLabels == FloatingPosition::Min) {
|
||||
position = KDPoint(k_labelMargin, position.y());
|
||||
} else if (floatingLabels == FloatingPosition::Min) {
|
||||
} else if (floatingLabels == FloatingPosition::Max) {
|
||||
position = KDPoint(Ion::Display::Width - textSize.width() - k_labelMargin, position.y());
|
||||
}
|
||||
}
|
||||
@@ -386,7 +386,7 @@ DrawLabel:
|
||||
}
|
||||
}
|
||||
|
||||
void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const {
|
||||
void CurveView::drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const {
|
||||
KDCoordinate min = (axis == Axis::Horizontal) ? rect.x() : rect.y();
|
||||
KDCoordinate max = (axis == Axis::Horizontal) ? rect.x() + rect.width() : rect.y() + rect.height();
|
||||
KDCoordinate start = std::isinf(lowerBound) ? min : std::round(floatToPixel(axis, lowerBound));
|
||||
@@ -417,6 +417,14 @@ void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coord
|
||||
}
|
||||
}
|
||||
|
||||
void CurveView::drawSegment(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick) const {
|
||||
float pxf = floatToPixel(Axis::Horizontal, x);
|
||||
float pyf = floatToPixel(Axis::Vertical, y);
|
||||
float puf = floatToPixel(Axis::Horizontal, u);
|
||||
float pvf = floatToPixel(Axis::Vertical, v);
|
||||
straightJoinDots(ctx, rect, pxf, pyf, puf, pvf, color, thick);
|
||||
}
|
||||
|
||||
void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size) const {
|
||||
KDCoordinate diameter = 0;
|
||||
const uint8_t * mask = nullptr;
|
||||
@@ -444,6 +452,47 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor
|
||||
ctx->blendRectWithMask(dotRect, color, mask, workingBuffer);
|
||||
}
|
||||
|
||||
|
||||
void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength, float angle) const {
|
||||
/* Let's call the following variables L and l:
|
||||
*
|
||||
* / |
|
||||
* / |
|
||||
* / l
|
||||
* / |
|
||||
* / |
|
||||
* <--------------------------------------------------
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
*
|
||||
* ----- L -----
|
||||
*
|
||||
**/
|
||||
assert(angle >= 0.0f);
|
||||
/* We compute the arrow segments in pixels in order to correctly size the
|
||||
* arrow without depending on the displayed range.
|
||||
* Warning: the computed values are relative so we need to add/subtract the
|
||||
* pixel position of 0s. */
|
||||
float x0Pixel = floatToPixel(Axis::Horizontal, 0.0f);
|
||||
float y0Pixel = floatToPixel(Axis::Vertical, 0.0f);
|
||||
float dxPixel = floatToPixel(Axis::Horizontal, dx) - x0Pixel;
|
||||
float dyPixel = y0Pixel - floatToPixel(Axis::Vertical, dy);
|
||||
float dx2dy2 = std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel);
|
||||
float L = pixelArrowLength;
|
||||
float l = angle*L;
|
||||
|
||||
float arrow1dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 + l*dyPixel/dx2dy2);
|
||||
float arrow1dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 - l*dxPixel/dx2dy2));
|
||||
drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false);
|
||||
|
||||
float arrow2dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 - l*dyPixel/dx2dy2);
|
||||
float arrow2dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 + l*dxPixel/dx2dy2));
|
||||
drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false);
|
||||
}
|
||||
|
||||
void CurveView::drawGrid(KDContext * ctx, KDRect rect) const {
|
||||
KDColor boldColor = Palette::GridPrimaryLine;
|
||||
KDColor lightColor = Palette::GridSecondaryLine;
|
||||
@@ -537,7 +586,7 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd
|
||||
x = xy.x1();
|
||||
y = xy.x2();
|
||||
if (colorUnderCurve && !std::isnan(x) && colorLowerBound < x && x < colorUpperBound && !(std::isnan(y) || std::isinf(y))) {
|
||||
drawSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1);
|
||||
}
|
||||
joinDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, previousT, previousX, previousY, t, x, y, color, thick, k_maxNumberOfIterations);
|
||||
} while (true);
|
||||
|
||||
@@ -38,8 +38,8 @@ public:
|
||||
void setBannerView(View * bannerView);
|
||||
void setOkView(View * okView);
|
||||
void setForceOkDisplay(bool force) { m_forceOkDisplay = force; }
|
||||
const float pixelWidth() const;
|
||||
const float pixelHeight() const;
|
||||
float pixelWidth() const;
|
||||
float pixelHeight() const;
|
||||
protected:
|
||||
CurveViewRange * curveViewRange() const { return m_curveViewRange; }
|
||||
void setCurveViewRange(CurveViewRange * curveViewRange);
|
||||
@@ -59,18 +59,47 @@ protected:
|
||||
float floatToPixel(Axis axis, float f) const;
|
||||
void drawLine(KDContext * ctx, KDRect rect, Axis axis,
|
||||
float coordinate, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const {
|
||||
return drawSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color,
|
||||
return drawHorizontalOrVerticalSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color,
|
||||
thickness, dashSize);
|
||||
}
|
||||
void drawSegment(KDContext * ctx, KDRect rect, Axis axis,
|
||||
void drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis,
|
||||
float coordinate, float lowerBound, float upperBound,
|
||||
KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const;
|
||||
void drawSegment(KDContext * ctx, KDRect rect,
|
||||
float x, float y, float u, float v,
|
||||
KDColor color, bool thick = true
|
||||
) const;
|
||||
enum class Size : uint8_t {
|
||||
Small,
|
||||
Medium,
|
||||
Large
|
||||
};
|
||||
void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const;
|
||||
/* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the
|
||||
* orientation (dx,dy).
|
||||
* The parameters defining the shape of the arrow are the length in pixel of
|
||||
* the projection of the arrow on the segment -'pixelArrowLength'- and the
|
||||
* tangent of the angle between the segment and each wing of the arrow called
|
||||
* 'angle'.
|
||||
*
|
||||
* / |
|
||||
* / |
|
||||
* / L
|
||||
* / |
|
||||
* / |
|
||||
* <--------------------------------------------------
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
* \
|
||||
*
|
||||
* <--- pl --->
|
||||
*
|
||||
* pl = pixelArrowLength
|
||||
* tan(angle) = L/pl
|
||||
*/
|
||||
void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength = 10, float angle = 0.4f) const;
|
||||
void drawGrid(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxes(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const;
|
||||
@@ -100,7 +129,7 @@ private:
|
||||
float min(Axis axis) const;
|
||||
float max(Axis axis) const;
|
||||
float gridUnit(Axis axis) const;
|
||||
virtual char * label(Axis axis, int index) const = 0;
|
||||
virtual char * label(Axis axis, int index) const { return nullptr; }
|
||||
virtual size_t labelMaxGlyphLengthSize() const { return k_labelBufferMaxGlyphLength; }
|
||||
int numberOfLabels(Axis axis) const;
|
||||
/* Recursively join two dots (dichotomy). The method stops when the
|
||||
|
||||
@@ -17,8 +17,8 @@ public:
|
||||
virtual float xMax() const = 0;
|
||||
virtual float yMin() const = 0;
|
||||
virtual float yMax() const = 0;
|
||||
const float xCenter() const { return (xMin() + xMax()) / 2; }
|
||||
const float yCenter() const { return (yMin() + yMax()) / 2; }
|
||||
float xCenter() const { return (xMin() + xMax()) / 2; }
|
||||
float yCenter() const { return (yMin() + yMax()) / 2; }
|
||||
virtual float xGridUnit() const {
|
||||
return computeGridUnit(k_minNumberOfXGridUnits, k_maxNumberOfXGridUnits, xMax() - xMin());
|
||||
}
|
||||
|
||||
@@ -55,10 +55,12 @@ public:
|
||||
// Colors
|
||||
static KDColor colorOfSeriesAtIndex(int i) {
|
||||
assert(i >= 0 && i < k_numberOfSeries);
|
||||
assert(i < Palette::numberOfDataColors());
|
||||
return Palette::DataColor[i];
|
||||
}
|
||||
static KDColor colorLightOfSeriesAtIndex(int i) {
|
||||
assert(i >= 0 && i < k_numberOfSeries);
|
||||
assert(i < Palette::numberOfLightDataColors());
|
||||
return Palette::DataColorLight[i];
|
||||
}
|
||||
protected:
|
||||
|
||||
@@ -11,11 +11,14 @@ FunctionApp::Snapshot::Snapshot() :
|
||||
m_rangeVersion(0),
|
||||
m_angleUnitVersion(Preferences::AngleUnit::Radian)
|
||||
{
|
||||
assert(m_previousModelsVersions[0] == 0);
|
||||
}
|
||||
|
||||
void FunctionApp::Snapshot::reset() {
|
||||
m_indexFunctionSelectedByCursor = 0;
|
||||
m_modelVersion = 0;
|
||||
assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * FunctionGraphController::sNumberOfMemoizedModelVersions);
|
||||
memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions));
|
||||
m_rangeVersion = 0;
|
||||
setActiveTab(0);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SHARED_FUNCTION_APP_H
|
||||
|
||||
#include "expression_field_delegate_app.h"
|
||||
#include "function_graph_controller.h"
|
||||
#include "function_store.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "values_controller.h"
|
||||
@@ -15,6 +16,7 @@ public:
|
||||
Snapshot();
|
||||
CurveViewCursor * cursor() { return &m_cursor; }
|
||||
uint32_t * modelVersion() { return &m_modelVersion; }
|
||||
uint32_t * previousModelsVersions() { return m_previousModelsVersions; }
|
||||
uint32_t * rangeVersion() { return &m_rangeVersion; }
|
||||
Poincare::Preferences::AngleUnit * angleUnitVersion() { return &m_angleUnitVersion; }
|
||||
virtual FunctionStore * functionStore() = 0;
|
||||
@@ -26,6 +28,7 @@ public:
|
||||
private:
|
||||
int m_indexFunctionSelectedByCursor;
|
||||
uint32_t m_modelVersion;
|
||||
uint32_t m_previousModelsVersions[FunctionGraphController::sNumberOfMemoizedModelVersions];
|
||||
uint32_t m_rangeVersion;
|
||||
Poincare::Preferences::AngleUnit m_angleUnitVersion;
|
||||
};
|
||||
|
||||
@@ -15,8 +15,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; }
|
||||
static inline double minDouble(double x, double y) { return x < y ? x : y; }
|
||||
static inline double maxDouble(double x, double y) { return x > y ? x : y; }
|
||||
|
||||
FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) :
|
||||
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion),
|
||||
FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) :
|
||||
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, previousModelsVersions, rangeVersion),
|
||||
m_initialisationParameterController(this, interactiveRange),
|
||||
m_angleUnitVersion(angleUnitVersion),
|
||||
m_indexFunctionSelectedByCursor(indexFunctionSelectedByCursor)
|
||||
@@ -183,6 +183,10 @@ uint32_t FunctionGraphController::modelVersion() {
|
||||
return functionStore()->storeChecksum();
|
||||
}
|
||||
|
||||
uint32_t FunctionGraphController::modelVersionAtIndex(size_t i) {
|
||||
return functionStore()->storeChecksumAtIndex(i);
|
||||
}
|
||||
|
||||
uint32_t FunctionGraphController::rangeVersion() {
|
||||
return interactiveCurveViewRange()->rangeChecksum();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace Shared {
|
||||
|
||||
class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate {
|
||||
public:
|
||||
FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion);
|
||||
static constexpr size_t sNumberOfMemoizedModelVersions = 5;
|
||||
FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion);
|
||||
bool isEmpty() const override;
|
||||
ViewController * initialisationParameterController() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
@@ -49,7 +50,9 @@ private:
|
||||
// InteractiveCurveViewController
|
||||
bool moveCursorVertically(int direction) override;
|
||||
uint32_t modelVersion() override;
|
||||
uint32_t modelVersionAtIndex(size_t i) override;
|
||||
uint32_t rangeVersion() override;
|
||||
size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; }
|
||||
|
||||
InitialisationParameterController m_initialisationParameterController;
|
||||
Poincare::Preferences::AngleUnit * m_angleUnitVersion;
|
||||
|
||||
@@ -8,13 +8,11 @@ namespace Shared {
|
||||
|
||||
FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange,
|
||||
CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView) :
|
||||
CurveView(graphRange, cursor, bannerView, cursorView),
|
||||
LabeledCurveView(graphRange, cursor, bannerView, cursorView),
|
||||
m_selectedRecord(),
|
||||
m_highlightedStart(NAN),
|
||||
m_highlightedEnd(NAN),
|
||||
m_shouldColorHighlighted(false),
|
||||
m_xLabels{},
|
||||
m_yLabels{},
|
||||
m_context(nullptr)
|
||||
{
|
||||
}
|
||||
@@ -67,10 +65,6 @@ void FunctionGraphView::setAreaHighlightColor(bool highlightColor) {
|
||||
}
|
||||
}
|
||||
|
||||
char * FunctionGraphView::label(Axis axis, int index) const {
|
||||
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
|
||||
}
|
||||
|
||||
void FunctionGraphView::reloadBetweenBounds(float start, float end) {
|
||||
if (start == end) {
|
||||
return;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
#define SHARED_FUNCTION_GRAPH_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "curve_view.h"
|
||||
#include "labeled_curve_view.h"
|
||||
#include "function.h"
|
||||
#include "../constant.h"
|
||||
#include "interactive_curve_view_range.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionGraphView : public CurveView {
|
||||
class FunctionGraphView : public LabeledCurveView {
|
||||
public:
|
||||
FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor,
|
||||
BannerView * bannerView, CursorView * cursorView);
|
||||
@@ -26,9 +26,6 @@ protected:
|
||||
float m_highlightedEnd;
|
||||
bool m_shouldColorHighlighted;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
Poincare::Context * m_context;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,4 +6,11 @@ uint32_t FunctionStore::storeChecksum() {
|
||||
return Ion::Storage::sharedStorage()->checksum();
|
||||
}
|
||||
|
||||
uint32_t FunctionStore::storeChecksumAtIndex(size_t i) {
|
||||
if (numberOfActiveFunctions() <= i) {
|
||||
return 0;
|
||||
}
|
||||
return activeRecordAtIndex(i).checksum();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class FunctionStore : public ExpressionModelStore {
|
||||
public:
|
||||
FunctionStore() : ExpressionModelStore() {}
|
||||
uint32_t storeChecksum();
|
||||
uint32_t storeChecksumAtIndex(size_t i);
|
||||
int numberOfActiveFunctions() const {
|
||||
return numberOfModelsSatisfyingTest(&isFunctionActive, nullptr);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion) :
|
||||
InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion) :
|
||||
SimpleInteractiveCurveViewController(parentResponder, cursor),
|
||||
ButtonRowDelegate(header, nullptr),
|
||||
m_modelVersion(modelVersion),
|
||||
m_previousModelsVersions(previousModelsVersions),
|
||||
m_rangeVersion(rangeVersion),
|
||||
m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange),
|
||||
m_zoomParameterController(this, interactiveRange, curveView),
|
||||
@@ -132,11 +133,43 @@ Responder * InteractiveCurveViewController::defaultController() {
|
||||
return tabController();
|
||||
}
|
||||
|
||||
bool InteractiveCurveViewController::previousModelsWereAllDeleted() {
|
||||
bool result = true;
|
||||
const int modelsCount = numberOfCurves();
|
||||
const int memoizationCount = numberOfMemoizedVersions();
|
||||
|
||||
// Look for a current model that is the same as in the previous version
|
||||
for (int i = 0; i < modelsCount; i++) {
|
||||
uint32_t currentVersion = modelVersionAtIndex(i);
|
||||
for (int j = 0; j < memoizationCount; j++) {
|
||||
uint32_t * previousVersion = m_previousModelsVersions + j;
|
||||
if (currentVersion == *previousVersion) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the memoization
|
||||
for (int i = 0; i < memoizationCount; i++) {
|
||||
uint32_t * previousVersion = m_previousModelsVersions + i;
|
||||
uint32_t newVersion = modelVersionAtIndex(i);
|
||||
if (*previousVersion != newVersion) {
|
||||
*previousVersion = newVersion;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void InteractiveCurveViewController::viewWillAppear() {
|
||||
SimpleInteractiveCurveViewController::viewWillAppear();
|
||||
uint32_t newModelVersion = modelVersion();
|
||||
if (*m_modelVersion != newModelVersion) {
|
||||
if (*m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) {
|
||||
// Put previousModelsWereAllDeleted first to update the model versions
|
||||
if (previousModelsWereAllDeleted() || *m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) {
|
||||
interactiveCurveViewRange()->setDefault();
|
||||
}
|
||||
*m_modelVersion = newModelVersion;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Shared {
|
||||
|
||||
class InteractiveCurveViewController : public SimpleInteractiveCurveViewController, public InteractiveCurveViewRangeDelegate, public ButtonRowDelegate, public AlternateEmptyViewDefaultDelegate {
|
||||
public:
|
||||
InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion);
|
||||
InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion);
|
||||
|
||||
const char * title() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
|
||||
Responder * defaultController() override;
|
||||
|
||||
bool previousModelsWereAllDeleted();
|
||||
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void willExitResponderChain(Responder * nextFirstResponder) override;
|
||||
@@ -39,6 +41,7 @@ protected:
|
||||
virtual void initCursorParameters() = 0;
|
||||
virtual bool moveCursorVertically(int direction) = 0;
|
||||
virtual uint32_t modelVersion() = 0;
|
||||
virtual uint32_t modelVersionAtIndex(size_t i) = 0;
|
||||
virtual uint32_t rangeVersion() = 0;
|
||||
bool isCursorVisible();
|
||||
|
||||
@@ -66,7 +69,9 @@ private:
|
||||
float addMargin(float x, float range, bool isVertical, bool isMin) override;
|
||||
|
||||
virtual bool shouldSetDefaultOnModelChange() const { return false; }
|
||||
virtual size_t numberOfMemoizedVersions() const = 0;
|
||||
uint32_t * m_modelVersion;
|
||||
uint32_t * m_previousModelsVersions;
|
||||
uint32_t * m_rangeVersion;
|
||||
RangeParameterController m_rangeParameterController;
|
||||
ZoomParameterController m_zoomParameterController;
|
||||
|
||||
31
apps/shared/labeled_curve_view.cpp
Normal file
31
apps/shared/labeled_curve_view.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "labeled_curve_view.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
char * HorizontallyLabeledCurveView::label(Axis axis, int index) const {
|
||||
if (axis == Axis::Horizontal) {
|
||||
assert(index < k_maxNumberOfXLabels);
|
||||
return m_xLabels[index];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char * VerticallyLabeledCurveView::label(Axis axis, int index) const {
|
||||
if (axis == Axis::Vertical) {
|
||||
assert(index < k_maxNumberOfYLabels);
|
||||
return m_yLabels[index];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char * LabeledCurveView::label(Axis axis, int index) const {
|
||||
if (axis == Axis::Horizontal) {
|
||||
assert(index < k_maxNumberOfXLabels);
|
||||
return m_xLabels[index];
|
||||
} else {
|
||||
assert(index < k_maxNumberOfYLabels);
|
||||
return m_yLabels[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
37
apps/shared/labeled_curve_view.h
Normal file
37
apps/shared/labeled_curve_view.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef SHARED_LABELED_CURVE_VIEW_H
|
||||
#define SHARED_LABELED_CURVE_VIEW_H
|
||||
|
||||
#include "curve_view.h"
|
||||
|
||||
/* This CurveView subclass provides label storage for common use cases */
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class HorizontallyLabeledCurveView : public CurveView {
|
||||
public:
|
||||
using CurveView::CurveView;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
};
|
||||
|
||||
class VerticallyLabeledCurveView : public CurveView {
|
||||
public:
|
||||
using CurveView::CurveView;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
};
|
||||
|
||||
class LabeledCurveView : public CurveView {
|
||||
public:
|
||||
using CurveView::CurveView;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -49,6 +49,14 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) {
|
||||
CursorView::setCursorFrame(f, force);
|
||||
}
|
||||
|
||||
void RoundCursorView::markRectAsDirty(KDRect rect) {
|
||||
/* The CursorView class inherits from TransparentView, so does
|
||||
* RoundCursorView. The method markRectAsDirty is thus overriden to avoid
|
||||
* marking as dirty the background of the RoundCursorView in its superview.
|
||||
*/
|
||||
View::markRectAsDirty(rect);
|
||||
}
|
||||
|
||||
#ifdef GRAPH_CURSOR_SPEEDUP
|
||||
bool RoundCursorView::eraseCursorIfPossible() {
|
||||
if (!m_underneathPixelBufferLoaded) {
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
void resetMemoization() const { m_underneathPixelBufferLoaded = false; }
|
||||
#endif
|
||||
private:
|
||||
void markRectAsDirty(KDRect rect) override;
|
||||
#ifdef GRAPH_CURSOR_SPEEDUP
|
||||
bool eraseCursorIfPossible();
|
||||
#endif
|
||||
|
||||
@@ -6,16 +6,6 @@ using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
SimpleInteractiveCurveViewController::SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) :
|
||||
ViewController(parentResponder),
|
||||
m_cursor(cursor)
|
||||
{
|
||||
}
|
||||
|
||||
View * SimpleInteractiveCurveViewController::view() {
|
||||
return curveView();
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
|
||||
return handleZoom(event);
|
||||
@@ -36,13 +26,6 @@ bool SimpleInteractiveCurveViewController::textFieldDidReceiveEvent(TextField *
|
||||
return TextFieldDelegate::textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleZoom(Ion::Events::Event event) {
|
||||
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
|
||||
interactiveCurveViewRange()->zoom(ratio, m_cursor->x(), m_cursor->y());
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleLeftRightEvent(Ion::Events::Event event) {
|
||||
int direction = event == Ion::Events::Left ? -1 : 1;
|
||||
if (moveCursorHorizontally(direction, Ion::Events::isLongRepetition())) {
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
#ifndef SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/view_controller.h>
|
||||
#include "text_field_delegate.h"
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "curve_view.h"
|
||||
#include "zoom_curve_view_controller.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* SimpleInteractiveCurveViewController is a View controller with a cursor that
|
||||
* can handles zoom in/out and left and right events. */
|
||||
|
||||
class SimpleInteractiveCurveViewController : public ViewController, public TextFieldDelegate {
|
||||
class SimpleInteractiveCurveViewController : public ZoomCurveViewController, public TextFieldDelegate {
|
||||
public:
|
||||
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor);
|
||||
View * view() override;
|
||||
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) : ZoomCurveViewController(parentResponder), m_cursor(cursor) {}
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
@@ -24,15 +20,15 @@ protected:
|
||||
virtual float cursorTopMarginRatio() { return 0.07f; } // (cursorHeight/2)/(graphViewHeight-1)
|
||||
virtual float cursorBottomMarginRatio() = 0; // (cursorHeight/2+bannerHeight)/(graphViewHeight-1)
|
||||
constexpr static float k_numberOfCursorStepsInGradUnit = 5.0f;
|
||||
virtual bool handleZoom(Ion::Events::Event event);
|
||||
// ZoomCurveViewController
|
||||
float xFocus() override { return m_cursor->x(); }
|
||||
float yFocus() override { return m_cursor->y(); }
|
||||
virtual bool handleLeftRightEvent(Ion::Events::Event event);
|
||||
virtual void reloadBannerView() = 0;
|
||||
/* the result of moveCursorVertically/Horizontally means:
|
||||
* false -> the cursor cannot move in this direction
|
||||
* true -> the cursor moved */
|
||||
virtual bool moveCursorHorizontally(int direction, bool fast = false) { return false; }
|
||||
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
|
||||
virtual CurveView * curveView() = 0;
|
||||
virtual bool handleEnter() = 0;
|
||||
CurveViewCursor * m_cursor;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <poincare/empty_layout.h>
|
||||
#include <poincare/condensed_sum_layout.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include "poincare_helpers.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -150,14 +149,13 @@ void SumGraphController::reloadBannerView() {
|
||||
m_legendView.setEditableZone(m_cursor->x());
|
||||
result = NAN;
|
||||
}
|
||||
m_legendView.setSumSymbol(m_step, m_startSum, endSum, result, functionLayout);
|
||||
m_legendView.setSumLayout(m_step, m_startSum, endSum, result, functionLayout);
|
||||
}
|
||||
|
||||
/* Legend View */
|
||||
|
||||
SumGraphController::LegendView::LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol) :
|
||||
m_sum(0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
|
||||
m_sumLayout(),
|
||||
m_legend(k_font, I18n::Message::Default, 0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
|
||||
m_editableZone(controller, m_textBuffer, k_editableZoneBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, controller, k_font, 0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
|
||||
m_sumSymbol(sumSymbol)
|
||||
@@ -179,54 +177,41 @@ void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Ste
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::setEditableZone(double d) {
|
||||
constexpr int precision = Preferences::MediumNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char buffer[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
|
||||
char buffer[k_valuesBufferSize];
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(d, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
|
||||
m_editableZone.setText(buffer);
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) {
|
||||
void SumGraphController::LegendView::setSumLayout(Step step, double start, double end, double result, Layout functionLayout) {
|
||||
assert(step == Step::Result || functionLayout.isUninitialized());
|
||||
constexpr int sigmaLength = 2;
|
||||
const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol};
|
||||
if (step == Step::FirstParameter) {
|
||||
m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength);
|
||||
} else if (step == Step::SecondParameter) {
|
||||
constexpr int precision = Preferences::MediumNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char buffer[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
|
||||
m_sumLayout = CondensedSumLayout::Builder(
|
||||
LayoutHelper::CodePointString(sigma, sigmaLength),
|
||||
Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength);
|
||||
if (step != Step::FirstParameter) {
|
||||
char buffer[k_valuesBufferSize];
|
||||
Layout endLayout;
|
||||
if (step == Step::SecondParameter) {
|
||||
endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false);
|
||||
} else {
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(end, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
|
||||
endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font);
|
||||
}
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
|
||||
sumLayout = CondensedSumLayout::Builder(
|
||||
sumLayout,
|
||||
LayoutHelper::String(buffer, strlen(buffer), k_font),
|
||||
EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false));
|
||||
} else {
|
||||
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
|
||||
constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
constexpr int bufferSize = 2 + sizeForPrecision;
|
||||
char buffer[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
|
||||
Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font);
|
||||
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
|
||||
Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font);
|
||||
m_sumLayout = CondensedSumLayout::Builder(
|
||||
LayoutHelper::CodePointString(sigma, sigmaLength),
|
||||
start,
|
||||
end);
|
||||
strlcpy(buffer, "= ", 3);
|
||||
PoincareHelpers::ConvertFloatToText<double>(result, buffer+2, bufferSize-2, precision);
|
||||
m_sumLayout = HorizontalLayout::Builder(
|
||||
m_sumLayout,
|
||||
functionLayout,
|
||||
LayoutHelper::String(buffer, strlen(buffer), k_font));
|
||||
}
|
||||
m_sum.setLayout(m_sumLayout);
|
||||
if (step == Step::Result) {
|
||||
m_sum.setAlignment(0.5f, 0.5f);
|
||||
} else {
|
||||
m_sum.setAlignment(0.0f, 0.5f);
|
||||
endLayout);
|
||||
if (step == Step::Result) {
|
||||
PoincareHelpers::ConvertFloatToText<double>(result, buffer, k_valuesBufferSize, k_valuesPrecision);
|
||||
sumLayout = HorizontalLayout::Builder(
|
||||
sumLayout,
|
||||
functionLayout,
|
||||
LayoutHelper::String("= ", 2, k_font),
|
||||
LayoutHelper::String(buffer, strlen(buffer), k_font));
|
||||
}
|
||||
}
|
||||
m_sum.setLayout(sumLayout);
|
||||
m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f);
|
||||
layoutSubviews(step, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,11 @@ private:
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setLegendMessage(I18n::Message message, Step step);
|
||||
void setEditableZone(double d);
|
||||
void setSumSymbol(Step step, double start, double end, double result, Poincare::Layout functionLayout);
|
||||
void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout);
|
||||
private:
|
||||
constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize;
|
||||
constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize;
|
||||
constexpr static int k_valuesPrecision = Poincare::Preferences::MediumNumberOfSignificantDigits;
|
||||
constexpr static int k_valuesBufferSize = Poincare::PrintFloat::charSizeForFloatsWithPrecision(k_valuesPrecision);
|
||||
constexpr static KDCoordinate k_legendHeight = 35;
|
||||
constexpr static const KDFont * k_font = KDFont::SmallFont;
|
||||
static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); }
|
||||
@@ -69,7 +71,6 @@ private:
|
||||
void layoutSubviews(bool force = false) override;
|
||||
void layoutSubviews(Step step, bool force);
|
||||
ExpressionView m_sum;
|
||||
Poincare::Layout m_sumLayout;
|
||||
MessageTextView m_legend;
|
||||
TextField m_editableZone;
|
||||
char m_textBuffer[k_editableZoneBufferSize];
|
||||
|
||||
35
apps/shared/zoom_and_pan_curve_view_controller.cpp
Normal file
35
apps/shared/zoom_and_pan_curve_view_controller.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "zoom_and_pan_curve_view_controller.h"
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ZoomAndPanCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Left || event == Ion::Events::Right || event == Ion::Events::Up || event == Ion::Events::Down) {
|
||||
return handlePan(event);
|
||||
}
|
||||
return ZoomCurveViewController::handleEvent(event);
|
||||
}
|
||||
|
||||
bool ZoomAndPanCurveViewController::handlePan(Ion::Events::Event event) {
|
||||
float xMove = 0.0f;
|
||||
float yMove = 0.0f;
|
||||
if (event == Ion::Events::Up) {
|
||||
yMove = interactiveCurveViewRange()->yGridUnit();
|
||||
} else if (event == Ion::Events::Down) {
|
||||
yMove = -interactiveCurveViewRange()->yGridUnit();
|
||||
} else if (event == Ion::Events::Left) {
|
||||
xMove = -interactiveCurveViewRange()->xGridUnit();
|
||||
} else {
|
||||
assert(event == Ion::Events::Right);
|
||||
xMove = interactiveCurveViewRange()->xGridUnit();
|
||||
}
|
||||
interactiveCurveViewRange()->panWithVector(xMove, yMove);
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
apps/shared/zoom_and_pan_curve_view_controller.h
Normal file
23
apps/shared/zoom_and_pan_curve_view_controller.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include "zoom_curve_view_controller.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* ZoomAndPanCurveViewController is a View controller with a cursor that can
|
||||
* handles zoom in/out and directional pan events. */
|
||||
|
||||
class ZoomAndPanCurveViewController : public ZoomCurveViewController {
|
||||
public:
|
||||
ZoomAndPanCurveViewController(Responder * parentResponder) : ZoomCurveViewController(parentResponder) {}
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool handlePan(Ion::Events::Event event);
|
||||
float xFocus() override { return interactiveCurveViewRange()->xCenter(); }
|
||||
float yFocus() override { return interactiveCurveViewRange()->yCenter(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
23
apps/shared/zoom_curve_view_controller.cpp
Normal file
23
apps/shared/zoom_curve_view_controller.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "zoom_curve_view_controller.h"
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ZoomCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
|
||||
return handleZoom(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZoomCurveViewController::handleZoom(Ion::Events::Event event) {
|
||||
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
|
||||
interactiveCurveViewRange()->zoom(ratio, xFocus(), yFocus());
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
30
apps/shared/zoom_curve_view_controller.h
Normal file
30
apps/shared/zoom_curve_view_controller.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/view_controller.h>
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "curve_view.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* ZoomCurveViewController is a View controller with a cursor that can handles
|
||||
* zoom in/out events. */
|
||||
|
||||
class ZoomCurveViewController : public ViewController {
|
||||
public:
|
||||
ZoomCurveViewController(Responder * parentResponder) : ViewController(parentResponder) {}
|
||||
View * view() override { return curveView(); }
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool handleZoom(Ion::Events::Event event);
|
||||
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
|
||||
virtual CurveView * curveView() = 0;
|
||||
virtual float xFocus() = 0;
|
||||
virtual float yFocus() = 0;
|
||||
CurveViewCursor * m_cursor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace Shared {
|
||||
|
||||
ZoomParameterController::ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveRange, CurveView * curveView) :
|
||||
ViewController(parentResponder),
|
||||
ZoomAndPanCurveViewController(parentResponder),
|
||||
m_contentView(curveView),
|
||||
m_interactiveRange(interactiveRange)
|
||||
{
|
||||
@@ -15,45 +15,6 @@ const char * ZoomParameterController::title() {
|
||||
return I18n::translate(I18n::Message::Zoom);
|
||||
}
|
||||
|
||||
View * ZoomParameterController::view() {
|
||||
return &m_contentView;
|
||||
}
|
||||
|
||||
bool ZoomParameterController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus) {
|
||||
m_interactiveRange->zoom(2.0f/3.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Minus) {
|
||||
m_interactiveRange->zoom(3.0f/2.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Up) {
|
||||
m_interactiveRange->panWithVector(0.0f, m_interactiveRange->yGridUnit());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Down) {
|
||||
m_interactiveRange->panWithVector(0.0f, -m_interactiveRange->yGridUnit());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Left) {
|
||||
m_interactiveRange->panWithVector(-m_interactiveRange->xGridUnit(), 0.0f);
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Right) {
|
||||
m_interactiveRange->panWithVector(m_interactiveRange->xGridUnit(), 0.0f);
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZoomParameterController::viewWillAppear() {
|
||||
ViewController::viewWillAppear();
|
||||
m_contentView.curveView()->setOkView(nullptr);
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
#ifndef SHARED_ZOOM_PARAMETER_CONTROLLER_H
|
||||
#define SHARED_ZOOM_PARAMETER_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view.h"
|
||||
#include "zoom_and_pan_curve_view_controller.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ZoomParameterController : public ViewController {
|
||||
class ZoomParameterController : public ZoomAndPanCurveViewController {
|
||||
public:
|
||||
ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveCurveViewRange, CurveView * curveView);
|
||||
const char * title() override;
|
||||
View * view() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
View * view() override { return &m_contentView; }
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
TELEMETRY_ID("Zoom");
|
||||
private:
|
||||
constexpr static KDCoordinate k_standardViewHeight = 175;
|
||||
|
||||
class ContentView : public View {
|
||||
public:
|
||||
constexpr static KDCoordinate k_legendHeight = 30;
|
||||
@@ -46,7 +44,13 @@ private:
|
||||
CurveView * m_curveView;
|
||||
LegendView m_legendView;
|
||||
};
|
||||
|
||||
void adaptCurveRange(bool viewWillAppear);
|
||||
|
||||
// ZoomAndPanCurveViewController
|
||||
InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_interactiveRange; }
|
||||
CurveView * curveView() override { return m_contentView.curveView(); }
|
||||
|
||||
ContentView m_contentView;
|
||||
InteractiveCurveViewRange * m_interactiveRange;
|
||||
};
|
||||
|
||||
@@ -211,7 +211,16 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex
|
||||
// Step 3. Polynomial & Monovariable?
|
||||
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
|
||||
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
|
||||
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit(), replaceFunctionsButNotSymbols ? ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions : ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
||||
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols)
|
||||
.getPolynomialReducedCoefficients(
|
||||
m_variables[0],
|
||||
polynomialCoefficients,
|
||||
context,
|
||||
updatedComplexFormat(context),
|
||||
preferences->angleUnit(),
|
||||
replaceFunctionsButNotSymbols ?
|
||||
ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions :
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
||||
if (degree == 2) {
|
||||
// Polynomial degree <= 2
|
||||
m_type = Type::PolynomialMonovariable;
|
||||
@@ -262,7 +271,9 @@ EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolution
|
||||
Preferences::AngleUnit angleUnit = Preferences::sharedPreferences()->angleUnit();
|
||||
// n unknown variables
|
||||
int n = 0;
|
||||
while (m_variables[n][0] != 0) { n++; }
|
||||
while (n < Expression::k_maxNumberOfVariables && m_variables[n][0] != 0) {
|
||||
n++;
|
||||
}
|
||||
int m = numberOfDefinedModels(); // m equations
|
||||
/* Create the matrix (A | b) for the equation Ax=b */
|
||||
Matrix Ab = Matrix::Builder();
|
||||
|
||||
@@ -12,8 +12,4 @@ void BoxAxisView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, false, true, k_axisMargin);
|
||||
}
|
||||
|
||||
char * BoxAxisView::label(Axis axis, int index) const {
|
||||
return axis == Axis::Vertical ? nullptr : (char *)m_labels[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,24 +3,21 @@
|
||||
|
||||
#include "box_range.h"
|
||||
#include "store.h"
|
||||
#include "../shared/curve_view.h"
|
||||
#include "../shared/labeled_curve_view.h"
|
||||
#include "../constant.h"
|
||||
#include <poincare/print_float.h>
|
||||
|
||||
namespace Statistics {
|
||||
|
||||
class BoxAxisView : public Shared::CurveView {
|
||||
class BoxAxisView : public Shared::HorizontallyLabeledCurveView {
|
||||
public:
|
||||
BoxAxisView(Store * store) :
|
||||
CurveView(&m_boxRange),
|
||||
m_labels{},
|
||||
HorizontallyLabeledCurveView(&m_boxRange),
|
||||
m_boxRange(BoxRange(store))
|
||||
{}
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
constexpr static KDCoordinate k_axisMargin = 3;
|
||||
char * label(Axis axis, int index) const override;
|
||||
char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
BoxRange m_boxRange;
|
||||
};
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// Draw the horizontal lines linking the box to the extreme bounds
|
||||
KDColor horizontalColor = isMainViewSelected() ? m_selectedHistogramColor : Palette::SecondaryText;
|
||||
float segmentOrd = (lowBound + upBound)/ 2.0f;
|
||||
drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor);
|
||||
|
||||
double calculations[5] = {minVal, firstQuart, m_store->median(m_series), thirdQuart, maxVal};
|
||||
/* We then draw all the vertical lines of the box and then recolor the
|
||||
@@ -83,10 +83,10 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
* lines. This solution could hide the highlighted line by coloring the next
|
||||
* quantile if it has the same value. */
|
||||
for (int k = 0; k < 5; k++) {
|
||||
drawSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::StatisticsBoxVerticalLine, k_quantileBarWidth);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::StatisticsBoxVerticalLine, k_quantileBarWidth);
|
||||
}
|
||||
if (isMainViewSelected()) {
|
||||
drawSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::StatisticsBox, k_quantileBarWidth);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::StatisticsBox, k_quantileBarWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ private:
|
||||
static constexpr KDCoordinate k_quantileBarWidth = 2;
|
||||
KDCoordinate boxLowerBoundPixel() const;
|
||||
KDCoordinate boxUpperBoundPixel() const;
|
||||
char * label(Axis axis, int index) const override { return nullptr; }
|
||||
Store * m_store;
|
||||
BoxRange m_boxRange;
|
||||
int m_series;
|
||||
|
||||
@@ -8,10 +8,9 @@ using namespace Shared;
|
||||
namespace Statistics {
|
||||
|
||||
HistogramView::HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor, KDColor notSelectedHistogramColor, KDColor selectedBarColor) :
|
||||
CurveView(store, nullptr, bannerView, nullptr),
|
||||
HorizontallyLabeledCurveView(store, nullptr, bannerView, nullptr),
|
||||
m_controller(controller),
|
||||
m_store(store),
|
||||
m_labels{},
|
||||
m_highlightedBarStart(NAN),
|
||||
m_highlightedBarEnd(NAN),
|
||||
m_series(series),
|
||||
@@ -63,10 +62,6 @@ void HistogramView::setHighlight(float start, float end) {
|
||||
}
|
||||
}
|
||||
|
||||
char * HistogramView::label(Axis axis, int index) const {
|
||||
return axis == Axis::Vertical ? nullptr : (char *)m_labels[index];
|
||||
}
|
||||
|
||||
float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) {
|
||||
Store * store = (Store *)model;
|
||||
float totalSize = ((float *)context)[0];
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include <poincare/print_float.h>
|
||||
#include "store.h"
|
||||
#include "../constant.h"
|
||||
#include "../shared/curve_view.h"
|
||||
#include "../shared/labeled_curve_view.h"
|
||||
|
||||
namespace Statistics {
|
||||
|
||||
class HistogramController;
|
||||
|
||||
class HistogramView : public Shared::CurveView {
|
||||
class HistogramView : public Shared::HorizontallyLabeledCurveView {
|
||||
public:
|
||||
HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor = Palette::StatisticsSelected, KDColor notSelectedHistogramColor = Palette::StatisticsNotSelected, KDColor selectedBarColor = Palette::StatisticsSelected);
|
||||
int series() const { return m_series; }
|
||||
@@ -21,10 +21,8 @@ public:
|
||||
void setHighlight(float start, float end);
|
||||
void setDisplayLabels(bool display) { m_displayLabels = display; }
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
HistogramController * m_controller;
|
||||
Store * m_store;
|
||||
char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
static float EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context);
|
||||
float m_highlightedBarStart;
|
||||
float m_highlightedBarEnd;
|
||||
|
||||
@@ -7,8 +7,8 @@ LEDS_CHOICE ?= 0
|
||||
include build/defaults.mak
|
||||
include build/platform.$(PLATFORM).mak
|
||||
|
||||
EPSILON_VERSION ?= 13.0.0
|
||||
EPSILON_CUSTOM_VERSION ?= 1.19.1
|
||||
EPSILON_VERSION ?= 13.2.0
|
||||
EPSILON_CUSTOM_VERSION ?= 1.19.2
|
||||
# USERNAME ?= N/A
|
||||
EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings external
|
||||
EPSILON_I18N ?= en fr es de pt hu
|
||||
@@ -21,9 +21,6 @@ OMEGA_THEME ?= omega_light
|
||||
ifndef USE_LIBA
|
||||
$(error platform.mak should define USE_LIBA)
|
||||
endif
|
||||
ifndef EXE
|
||||
$(error platform.mak should define EXE, the extension for executables)
|
||||
endif
|
||||
include build/toolchain.$(TOOLCHAIN).mak
|
||||
|
||||
SFLAGS += -DDEBUG=$(DEBUG)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
TOOLCHAIN = android
|
||||
EXE = so
|
||||
|
||||
EPSILON_TELEMETRY ?= 1
|
||||
|
||||
ifdef NDK_ABI
|
||||
BUILD_DIR := $(BUILD_DIR)/$(NDK_ABI)
|
||||
ARCHS = armeabi-v7a arm64-v8a x86 x86_64
|
||||
|
||||
ifdef ARCH
|
||||
EXE = so
|
||||
BUILD_DIR := $(BUILD_DIR)/$(ARCH)
|
||||
endif
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
# Define standard compilation rules
|
||||
|
||||
.PHONY: official_authorization
|
||||
ifeq ($(ACCEPT_OFFICIAL_TOS),1)
|
||||
official_authorization:
|
||||
@echo "CAUTION: You are about to build an official NumWorks firmware. Distribution of such firmware by a third party is prohibited. Are you sure you want to proceed? Please type "yes" to confirm." && read ans && [ $${ans:-no} = yes ]
|
||||
else
|
||||
official_authorization:
|
||||
@echo "CAUTION: You are trying to build an official NumWorks firmware."
|
||||
@echo "Distribution of such firmware by a third party is prohibited."
|
||||
@echo "Please set the ACCEPT_OFFICIAL_TOS environment variable to proceed."
|
||||
@exit -1
|
||||
endif
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
AS, %.o, %.s, \
|
||||
@@ -31,6 +38,12 @@ $(eval $(call rule_for, \
|
||||
$$(CXX) $$(CXXFLAGS) $$(SFLAGS) -c $$< -o $$@ \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
CPP, %, %.inc, \
|
||||
$$(CPP) -P $$< $$@ \
|
||||
))
|
||||
|
||||
ifdef EXE
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Work around command-line length limit
|
||||
# On Msys2 the max command line is 32 000 characters. Our standard LD command
|
||||
@@ -47,6 +60,7 @@ $(eval $(call rule_for, \
|
||||
$$(LD) $$^ $$(LDFLAGS) -o $$@ \
|
||||
))
|
||||
endif
|
||||
endif
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
WINDRES, %.o, %.rc, \
|
||||
|
||||
@@ -29,32 +29,32 @@ all_official:
|
||||
$(call file_check,$(ANDROID_GRADLE_PROPERTIES))
|
||||
$(call file_check,$(IOS_MOBILE_PROVISION))
|
||||
$(call command_check,$(EMCC))
|
||||
$(Q) rm -rf output/stable_release
|
||||
$(Q) mkdir -p output/stable_release
|
||||
$(Q) rm -rf output/all_official
|
||||
$(Q) mkdir -p output/all_official
|
||||
$(Q) echo "BUILD_FIRMWARE DEVICE N0110"
|
||||
$(Q) $(MAKE) clean
|
||||
$(Q) $(MAKE) epsilon.official.onboarding.dfu
|
||||
$(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu
|
||||
$(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0110.dfu
|
||||
$(Q) echo "BUILD_FIRMWARE DEVICE N0100"
|
||||
$(Q) $(MAKE) MODEL=n0100 clean
|
||||
$(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu
|
||||
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu
|
||||
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0100.dfu
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP"
|
||||
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip
|
||||
$(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.zip
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.zip output/all_official/simulator.web.zip
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS"
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS"
|
||||
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID"
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=android clean
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk
|
||||
$(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.signed.apk
|
||||
$(Q) cp output/release/simulator/android/app/outputs/apk/codesigned/android-codesigned.apk output/all_official/epsilon.official.apk
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR IOS"
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa
|
||||
$(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE=$(IOS_MOBILE_PROVISION) output/release/simulator/ios/app/epsilon.official.ipa
|
||||
$(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/all_official/epsilon.ipa
|
||||
|
||||
@@ -20,28 +20,3 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex
|
||||
fi
|
||||
$(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^)
|
||||
|
||||
.PHONY: %.two_binaries
|
||||
%.two_binaries: %.elf
|
||||
@echo "Building an internal and an external binary for $<"
|
||||
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin
|
||||
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin
|
||||
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin
|
||||
|
||||
.PHONY: binpack
|
||||
binpack:
|
||||
rm -rf output/binpack
|
||||
mkdir -p output/binpack
|
||||
$(MAKE) clean
|
||||
$(MAKE) $(BUILD_DIR)/flasher.light.bin
|
||||
cp $(BUILD_DIR)/flasher.light.bin output/binpack
|
||||
$(MAKE) $(BUILD_DIR)/bench.flash.bin
|
||||
$(MAKE) $(BUILD_DIR)/bench.ram.bin
|
||||
cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack
|
||||
$(MAKE) epsilon.official.onboarding.update.two_binaries
|
||||
cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack
|
||||
$(MAKE) clean
|
||||
cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done
|
||||
cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack
|
||||
rm -rf output/binpack
|
||||
|
||||
3
build/targets.simulator.android.mak
Normal file
3
build/targets.simulator.android.mak
Normal file
@@ -0,0 +1,3 @@
|
||||
ifndef ARCH
|
||||
HANDY_TARGETS_EXTENSIONS += apk
|
||||
endif
|
||||
@@ -1,6 +1,3 @@
|
||||
$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0
|
||||
HANDY_TARGETS_EXTENSIONS += zip
|
||||
|
||||
$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0
|
||||
|
||||
$(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src))
|
||||
$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src))
|
||||
|
||||
@@ -13,16 +13,16 @@ NDK_TOOLCHAIN_PATH = $(NDK_PATH)/toolchains/llvm/prebuilt/$(NDK_HOST_TAG)/bin
|
||||
# is no toolchain for those archs on those API levels. Let's enforce NDK_VERSION
|
||||
# at 21 for these archs, and 16 for the others.
|
||||
|
||||
ifeq ($(NDK_ABI),armeabi-v7a)
|
||||
ifeq ($(ARCH),armeabi-v7a)
|
||||
NDK_TARGET = armv7a-linux-androideabi
|
||||
NDK_VERSION = 16
|
||||
else ifeq ($(NDK_ABI),arm64-v8a)
|
||||
else ifeq ($(ARCH),arm64-v8a)
|
||||
NDK_TARGET = aarch64-linux-android
|
||||
NDK_VERSION = 21
|
||||
else ifeq ($(NDK_ABI),x86)
|
||||
else ifeq ($(ARCH),x86)
|
||||
NDK_TARGET = i686-linux-android
|
||||
NDK_VERSION = 16
|
||||
else ifeq ($(NDK_ABI),x86_64)
|
||||
else ifeq ($(ARCH),x86_64)
|
||||
NDK_TARGET = x86_64-linux-android
|
||||
NDK_VERSION = 21
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CC = emcc
|
||||
CXX = emcc
|
||||
LD = emcc
|
||||
CPP = cpp
|
||||
|
||||
EMSCRIPTEN_ASYNC_SYMBOLS = \
|
||||
SAFE_HEAP_LOAD \
|
||||
@@ -120,20 +121,9 @@ endif
|
||||
# Configure EMFLAGS
|
||||
EMFLAGS += -s WASM=0
|
||||
|
||||
# Since emcc 1.39.5, DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is defautly
|
||||
# to 1 which discards old looks up to find DOM elements. However SDL relies on
|
||||
# the presence of a target "#canvas" that used to return the Module['canvas']
|
||||
# target but not anymore. It also expects the existence of Module['canvas'].
|
||||
# Until we fix the DOM of the html calling epsilon module, we use the deprecated
|
||||
# 'find_event_target'.
|
||||
# TODO: fix DOM of htmls files that uses epsilon js module
|
||||
EMFLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0
|
||||
|
||||
# Configure LDFLAGS
|
||||
EMSCRIPTEN_MODULARIZE ?= 1
|
||||
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"'
|
||||
EMSCRIPTEN_INIT_FILE ?= 1
|
||||
LDFLAGS += --memory-init-file $(EMSCRIPTEN_INIT_FILE)
|
||||
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"' --memory-init-file 0
|
||||
|
||||
SFLAGS += $(EMFLAGS)
|
||||
LDFLAGS += $(EMFLAGS) -Oz -s EXPORTED_FUNCTIONS='["_main", "_IonSimulatorKeyboardKeyDown", "_IonSimulatorKeyboardKeyUp", "_IonSimulatorEventsPushEvent", "_IonSoftwareVersion", "_IonPatchLevel", "_IonDisplayForceRefresh"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["UTF8ToString"]'
|
||||
|
||||
2
docs/build/index.md
vendored
2
docs/build/index.md
vendored
@@ -54,7 +54,7 @@ git clone https://github.com/numworks/epsilon.git
|
||||
|
||||
## Run Epsilon on your computer
|
||||
|
||||
Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm, etc...) and type the following commands:
|
||||
Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm…) and type the following commands:
|
||||
|
||||
```
|
||||
make PLATFORM=simulator clean
|
||||
|
||||
@@ -46,12 +46,11 @@ The choice of a programming language is a controversial topic. Not all of them c
|
||||
|
||||
- It is a [system](https://en.wikipedia.org/wiki/System_programming_language) programming language, which is something we need since we have to write some low-level code.
|
||||
- It has excellent tooling: several extremly high-quality compilers
|
||||
- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop, etc... This ensures a strong ecosystem of tools, code and documentation.
|
||||
- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop… This ensures a strong ecosystem of tools, code and documentation.
|
||||
- It easily allows Object-Oriented Programming, which is a convenient abstraction.
|
||||
|
||||
|
||||
Of course knowing a tool means knowing its limits. C++ isn't exempt of defaults:
|
||||
- It *is* a complicated language. The C++ 11 specification is 1300 pages long.
|
||||
- It *is* a complicated language. The C++ 11 specification is 1'300 pages long.
|
||||
- It allows for a lot of abstractions, which is a double-edged sword. It can allow for some very tricky code, and it's very easy to have complex operations being run without noticing.
|
||||
|
||||
If you want to contribute to Epsilon, you'll need to learn some C++.
|
||||
@@ -66,7 +65,7 @@ The stack memory is possibly the most used area of memory. It contains all local
|
||||
|
||||
#### Heap memory
|
||||
|
||||
Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of *malloc* / *free* functions.
|
||||
Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of `malloc` / `free` functions.
|
||||
|
||||
This raises a lot of potential problems that can trigger unpredictable dynamic behaviors:
|
||||
|
||||
@@ -77,7 +76,7 @@ This raises a lot of potential problems that can trigger unpredictable dynamic b
|
||||
<dd class="text-justify">Memory allocation has to be contiguous. So the allocation algorithm has to use a smart heuristic to ensure that it will not fragment its allocated space too much.</dd>
|
||||
</dl>
|
||||
|
||||
Some automatic memory management solutions do exist (garbage collection, smart pointers), but they all come with a cost. We decided to manually manage dynamic memory, but to use it as sparingly as possible.
|
||||
We decided to avoid `malloc` altogether and to use a mix of static allocation and a pool of relocatable garbage-collected nodes for manipulating mathematical expressions.
|
||||
|
||||
### Writing code that runs on the bare metal
|
||||
|
||||
@@ -90,8 +89,8 @@ In practice, this means that the firmware will need to know in advance how the m
|
||||
- Where will we store read-only variables?
|
||||
- Where will the code live in memory?
|
||||
|
||||
The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M4 devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678.
|
||||
The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678.
|
||||
|
||||
Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in "ion/src/device/boot/flash.ld" - it is heavily commented and should be self-explanatory.
|
||||
Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in [ion/src/device/n0110/flash.ld](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld) - it is heavily commented and should be self-explanatory.
|
||||
|
||||
That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the "ion/src/device/boot/rt0.cpp" file, which is worth reading too.
|
||||
That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the [ion/src/device/shared/boot/rt0.cpp](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/rt0.cpp) file, which is worth reading too.
|
||||
|
||||
@@ -11,25 +11,25 @@ By providing multiple implementations of the Ion functions, we therefore can get
|
||||
|
||||
## Device
|
||||
|
||||
This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our <a href="../../../hardware/electrical/">Electrical Engineering</a> pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device:
|
||||
This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our [Electrical Engineering](https://www.numworks.com/resources/engineering/hardware/electrical/) pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device:
|
||||
|
||||
### Boot
|
||||
|
||||
On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the <a href="https://github.com/numworks/epsilon/blob/master/ion/src/device/boot/isr.c">ISR table</a>.
|
||||
On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the [ISR table](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/isr.c).
|
||||
|
||||
### Memory layout
|
||||
|
||||
Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom <a href="https://github.com/numworks/epsilon/blob/master/ion/src/device/boot/flash.ld">linker script</a>.
|
||||
Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom [linker script](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld).
|
||||
|
||||
## Simulator
|
||||
|
||||
The simulator platform implements Ion calls using the <a href="http://www.fltk.org/">FLTK</a> library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions.
|
||||
The simulator platform implements Ion calls using the [SDL](https://www.libsdl.org/) library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions.
|
||||
|
||||
It's very practical to code using the simulator, but one has to pay attention to the differences from an actual device: it'll be significantly faster, and will have a lot more memory. So code written using the simulator should always be thoroughly tested on an actual device.
|
||||
|
||||
## Emscripten
|
||||
|
||||
The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our <a href="/simulator/">online simulator</a>. The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage.
|
||||
The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our [online simulator](https://www.numworks.com/simulator/). The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage.
|
||||
|
||||
Building on Emscripten takes quite a lot of time so you will most likely not want to use it for development purposes. But obviously it's a very neat feature for end users who can give the calculator a spin straight from their browser.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Poincare
|
||||
title: Poincaré
|
||||
---
|
||||
# Poincaré
|
||||
|
||||
@@ -9,7 +9,7 @@ Poincare takes text input such as `1+2*3` and turns it into a tree structure, th
|
||||
|
||||
Each node of a tree represents either an operator or a value. All nodes have a type (`Type::Addition`, `Type::Multiplication`...) and some also store a value (ie `Type::Rational`).
|
||||
|
||||
{:class="img-right"}
|
||||
{:class="img-right"}
|
||||
According to their types, expressions are childless (`Type::Rational`) or store pointers to their children (we call those children operands). To ease tree traversal, each node also keeps a pointer to its parent: that information is somewhat redundant but makes dealing with the expression tree much easier. `Multiplication` and `Addition` are the only type that can hold an infinite number of operands. Other expressions have a fixed number of operands: for instance, an `AbsoluteValue` will only ever have one child.
|
||||
|
||||
## RTTI: Run-time type information
|
||||
@@ -43,7 +43,6 @@ To sort those operands, we defined an order on expressions with the following fe
|
||||
* The order relationship is depth-first recursive: if two expressions are equal in type and values, we compare their operands starting with the last.
|
||||
* To compare two expressions, we first sort their commutative children to ensure the unicity of expression representations. This guarantees that the order is total on expressions.
|
||||
|
||||
|
||||
{:class="img-responsive"}
|
||||
In the example, both root nodes are r so we compare their last operands. Both are equal to $$\pi$$ so we compare the next operands. As 3 > 2, we can conclude on the order relation between the expressions.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user