[Git] Fix conflicts

This commit is contained in:
Quentin
2020-04-01 11:36:16 +02:00
60 changed files with 1568 additions and 223 deletions

View File

@@ -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 {
}, &parameters, &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);

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)"

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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) {

View File

@@ -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;
};
}

View File

@@ -19,6 +19,7 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
ScriptStore::ScriptStore()
{
addScriptFromTemplate(ScriptTemplate::Squares());
addScriptFromTemplate(ScriptTemplate::Parabola());
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
addScriptFromTemplate(ScriptTemplate::Polynomial());
}

View File

@@ -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 &parabolaScriptTemplate;
}
}

View File

@@ -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; }

View File

@@ -2,6 +2,7 @@ CmathModule = "cmath"
IonModule = "ion"
KandinskyModule = "kandinsky"
MathModule = "math"
MatplotlibPyplotModule = "matplotlib.pyplot"
TimeModule = "time"
TurtleModule = "turtle"
ForLoopMenu = "For"

View File

@@ -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; }

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -407,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);

View File

@@ -22,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) {

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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 \
@@ -45,7 +48,6 @@ app_shared_src = $(addprefix apps/shared/,\
interactive_curve_view_controller.cpp \
interval.cpp \
interval_parameter_controller.cpp \
labeled_curve_view.cpp \
language_controller.cpp \
layout_field_delegate.cpp \
list_parameter_controller.cpp \

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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:

View File

@@ -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())) {

View File

@@ -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;
};

View 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;
}
}

View 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

View 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;
}
}

View 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

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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);
}
}

View File

@@ -0,0 +1,44 @@
#ifndef ESCHER_PALETTE_H
#define ESCHER_PALETTE_H
#include <kandinsky/color.h>
#include <stddef.h>
class Palette {
public:
constexpr static KDColor YellowDark = KDColor::RGB24(0xffb734);
constexpr static KDColor YellowLight = KDColor::RGB24(0xffcc7b);
constexpr static KDColor PurpleBright = KDColor::RGB24(0x656975);
constexpr static KDColor PurpleDark = KDColor::RGB24(0x414147);
constexpr static KDColor GreyWhite = KDColor::RGB24(0xf5f5f5);
constexpr static KDColor GreyBright = KDColor::RGB24(0xececec);
constexpr static KDColor GreyMiddle = KDColor::RGB24(0xd9d9d9);
constexpr static KDColor GreyDark = KDColor::RGB24(0xa7a7a7);
constexpr static KDColor GreyVeryDark = KDColor::RGB24(0x8c8c8c);
constexpr static KDColor Select = KDColor::RGB24(0xd4d7e0);
constexpr static KDColor SelectDark = KDColor::RGB24(0xb0b8d8);
constexpr static KDColor WallScreen = KDColor::RGB24(0xf7f9fa);
constexpr static KDColor WallScreenDark = KDColor::RGB24(0xe0e6ed);
constexpr static KDColor SubTab = KDColor::RGB24(0xb8bbc5);
constexpr static KDColor LowBattery = KDColor::RGB24(0xf30211);
constexpr static KDColor Red = KDColor::RGB24(0xff000c);
constexpr static KDColor RedLight = KDColor::RGB24(0xfe6363);
constexpr static KDColor Magenta = KDColor::RGB24(0xff0588);
constexpr static KDColor Turquoise = KDColor::RGB24(0x60c1ec);
constexpr static KDColor Pink = KDColor::RGB24(0xffabb6);
constexpr static KDColor Blue = KDColor::RGB24(0x5075f2);
constexpr static KDColor BlueLight = KDColor::RGB24(0x718fee);
constexpr static KDColor Orange = KDColor::RGB24(0xfe871f);
constexpr static KDColor Green = KDColor::RGB24(0x50c102);
constexpr static KDColor GreenLight = KDColor::RGB24(0x52db8f);
constexpr static KDColor Brown = KDColor::RGB24(0x8d7350);
constexpr static KDColor Purple = KDColor::RGB24(0x6e2d79);
constexpr static KDColor DataColor[] = {Red, Blue, Green, YellowDark, Magenta, Turquoise, Pink, Orange};
constexpr static KDColor DataColorLight[] = {RedLight, BlueLight, GreenLight, YellowLight};
constexpr static size_t numberOfDataColors() { return sizeof(DataColor)/sizeof(KDColor); }
constexpr static size_t numberOfLightDataColors() { return sizeof(DataColorLight)/sizeof(KDColor); }
static KDColor nextDataColor(int * colorIndex);
};
#endif

View File

@@ -18,6 +18,7 @@ public:
int depth();
View * view() override;
ViewController * topViewController();
const char * title() override;
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;

View File

@@ -1,4 +1,5 @@
#include <escher/palette.h>
#include <assert.h>
constexpr KDColor Palette::PrimaryText;
constexpr KDColor Palette::SecondaryText; // =GREYDARK
@@ -142,3 +143,11 @@ constexpr KDColor Palette::AtomReactiveNonmetal;
constexpr KDColor Palette::AtomNobleGas;
constexpr KDColor Palette::AtomTableLines;
constexpr KDColor Palette::AtomColor[];
KDColor Palette::nextDataColor(int * colorIndex) {
size_t nbOfColors = numberOfDataColors();
assert(*colorIndex < nbOfColors);
KDColor c = DataColor[*colorIndex];
*colorIndex = (*colorIndex + 1) % nbOfColors;
return c;
}

View File

@@ -92,6 +92,13 @@ const char * StackViewController::title() {
return vc->title();
}
ViewController * StackViewController::topViewController() {
if (m_numberOfChildren < 1) {
return nullptr;
}
return m_childrenFrame[m_numberOfChildren-1].viewController();
}
void StackViewController::push(ViewController * vc, KDColor textColor, KDColor backgroundColor, KDColor separatorColor) {
Frame frame = Frame(vc, textColor, backgroundColor, separatorColor);
/* Add the frame to the model */
@@ -112,7 +119,7 @@ void StackViewController::push(ViewController * vc, KDColor textColor, KDColor b
void StackViewController::pop() {
assert(m_numberOfChildren > 0);
ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController();
ViewController * vc = topViewController();
if (vc->title() != nullptr && vc->displayParameter() != ViewController::DisplayParameter::DoNotShowOwnTitle) {
m_view.popStack();
}
@@ -131,7 +138,7 @@ void StackViewController::pushModel(Frame frame) {
}
void StackViewController::setupActiveViewController() {
ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController();
ViewController * vc = topViewController();
vc->setParentResponder(this);
m_view.shouldDisplayStackHearders(vc->displayParameter() != ViewController::DisplayParameter::WantsMaximumSpace);
m_view.setContentView(vc->view());
@@ -141,7 +148,7 @@ void StackViewController::setupActiveViewController() {
}
void StackViewController::didBecomeFirstResponder() {
ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController();
ViewController * vc = topViewController();
Container::activeApp()->setFirstResponder(vc);
}
@@ -170,7 +177,7 @@ void StackViewController::viewWillAppear() {
}
}
/* Load the visible controller view */
ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController();
ViewController * vc = topViewController();
if (m_numberOfChildren > 0 && vc) {
m_view.setContentView(vc->view());
m_view.shouldDisplayStackHearders(vc->displayParameter() != ViewController::DisplayParameter::WantsMaximumSpace);
@@ -180,7 +187,7 @@ void StackViewController::viewWillAppear() {
}
void StackViewController::viewDidDisappear() {
ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController();
ViewController * vc = topViewController();
if (m_numberOfChildren > 0 && vc) {
vc->viewDidDisappear();
}

View File

@@ -134,6 +134,13 @@ port_src += $(addprefix python/port/,\
mod/ion/modion_table.cpp \
mod/kandinsky/modkandinsky.cpp \
mod/kandinsky/modkandinsky_table.c \
mod/matplotlib/modmatplotlib.cpp \
mod/matplotlib/modmatplotlib_table.c \
mod/matplotlib/pyplot/modpyplot.cpp \
mod/matplotlib/pyplot/modpyplot_table.c \
mod/matplotlib/pyplot/plot_controller.cpp \
mod/matplotlib/pyplot/plot_store.cpp \
mod/matplotlib/pyplot/plot_view.cpp \
mod/time/modtime.c \
mod/time/modtime_table.c \
mod/turtle/modturtle.cpp \

View File

@@ -130,6 +130,21 @@ Q(EE)
Q(Ans)
Q(EXE)
// Matplotlib QSTRs
Q(arrow)
Q(axis)
Q(bar)
Q(grid)
Q(grid)
Q(hist)
Q(plot)
Q(matplotlib)
Q(matplotlib.pyplot)
Q(pyplot)
Q(scatter)
Q(show)
Q(text)
// Turtle QSTRs
Q(turtle)
Q(forward)

View File

@@ -0,0 +1,13 @@
extern "C" {
#include "modmatplotlib.h"
#include "pyplot/modpyplot.h"
}
#include <assert.h>
// Internal functions
mp_obj_t modmatplotlib___init__() {
modpyplot___init__();
return mp_const_none;
}

View File

@@ -0,0 +1,3 @@
#include <py/obj.h>
mp_obj_t modmatplotlib___init__();

View File

@@ -0,0 +1,18 @@
#include "modmatplotlib.h"
extern const mp_obj_module_t modpyplot_module;
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modmatplotlib___init___obj, modmatplotlib___init__);
STATIC const mp_rom_map_elem_t modmatplotlib_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_matplotlib) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modmatplotlib___init___obj) },
{ MP_ROM_QSTR(MP_QSTR_pyplot), MP_ROM_PTR(&modpyplot_module) }
};
STATIC MP_DEFINE_CONST_DICT(modmatplotlib_module_globals, modmatplotlib_module_globals_table);
const mp_obj_module_t modmatplotlib_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&modmatplotlib_module_globals,
};

View File

@@ -0,0 +1,33 @@
#include "modpyplot.h"
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 2, modpyplot_hist);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 2, modpyplot_plot);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text);
STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) },
{ MP_ROM_QSTR(MP_QSTR_arrow), MP_ROM_PTR(&modpyplot_arrow_obj) },
{ MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) },
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) },
{ MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) },
{ MP_ROM_QSTR(MP_QSTR_hist), MP_ROM_PTR(&modpyplot_hist_obj) },
{ MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) },
{ MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) },
{ MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&modpyplot_text_obj) },
};
STATIC MP_DEFINE_CONST_DICT(modpyplot_module_globals, modpyplot_module_globals_table);
const mp_obj_module_t modpyplot_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&modpyplot_module_globals,
};

View File

@@ -0,0 +1,362 @@
extern "C" {
#include "modpyplot.h"
}
#include <assert.h>
#include <escher/palette.h>
#include "port.h"
#include "plot_controller.h"
Matplotlib::PlotStore * sPlotStore = nullptr;
Matplotlib::PlotController * sPlotController = nullptr;
static int paletteIndex = 0;
// Private helper
// Method to populate items with a scalar or an array argument
static size_t extractArgument(mp_obj_t arg, mp_obj_t ** items) {
size_t itemLength;
if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) {
mp_obj_get_array(arg, &itemLength, items);
} else {
itemLength = 1;
*items = m_new(mp_obj_t, 1);
(*items)[0] = arg;
}
return itemLength;
}
// Extract two scalar or array arguments and check for their strickly equal dimension
static size_t extractArgumentsAndCheckEqualSize(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) {
size_t xLength = extractArgument(x, xItems);
size_t yLength = extractArgument(y, yItems);
if (xLength != yLength) {
mp_raise_ValueError("x and y must be the same size");
}
return xLength;
}
/* Extract one scalar or array arguments and check that it is either:
* - of size 1
* - of the required size
*/
size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength, mp_obj_t ** items) {
size_t itemLength = extractArgument(arg, items);
if (itemLength > 1 && requiredlength > 1 && itemLength != requiredlength) {
mp_raise_ValueError("shape mismatch");
}
return itemLength;
}
// Internal functions
mp_obj_t modpyplot___init__() {
static Matplotlib::PlotStore plotStore;
static Matplotlib::PlotController plotController(&plotStore);
sPlotStore = &plotStore;
sPlotController = &plotController;
sPlotStore->flush();
paletteIndex = 0;
return mp_const_none;
}
void modpyplot_gc_collect() {
if (sPlotStore == nullptr) {
return;
}
MicroPython::collectRootsAtAddress(
reinterpret_cast<char *>(sPlotStore),
sizeof(Matplotlib::PlotStore)
);
}
void modpyplot_flush_used_heap() {
if (sPlotStore) {
// Clean the store object
sPlotStore->flush();
}
}
/* arrow(x,y,dx,dy)
* x, y, dx, dy scalars
* */
mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) {
assert(n_args == 4);
assert(sPlotStore != nullptr);
KDColor color = Palette::nextDataColor(&paletteIndex);
sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color, true); // TODO: use float_binary_op
return mp_const_none;
}
/* axis(arg)
* - arg = "on", "off", "auto"
* - arg = True, False
* - arg = [xmin, xmax, ymin, ymax], (xmin, xmax, ymin, ymax)
* Returns : (xmin, xmax, ymin, ymax) : float */
mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) {
assert(sPlotStore != nullptr);
if (n_args == 1) {
mp_obj_t arg = args[0];
if (mp_obj_is_str(arg)) {
if (mp_obj_str_equal(arg, mp_obj_new_str("on", 2))) {
sPlotStore->setAxesRequested(true);
} else if (mp_obj_str_equal(arg, mp_obj_new_str("off", 3))) {
sPlotStore->setAxesRequested(false);
} else if (mp_obj_str_equal(arg, mp_obj_new_str("auto", 4))) {
sPlotStore->setAxesRequested(true);
sPlotStore->setAxesAuto(true);
} else {
mp_raise_ValueError("Unrecognized string given to axis; try 'on', 'off' or 'auto'");
}
#warning Use mp_obj_is_bool when upgrading uPy
} else if (mp_obj_is_type(arg, &mp_type_bool)) {
sPlotStore->setAxesRequested(mp_obj_is_true(arg));
} else if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) {
mp_obj_t * items;
mp_obj_get_array_fixed_n(arg, 4, &items);
sPlotStore->setXMin(mp_obj_get_float(items[0]));
sPlotStore->setXMax(mp_obj_get_float(items[1]));
sPlotStore->setYMin(mp_obj_get_float(items[2]));
sPlotStore->setYMax(mp_obj_get_float(items[3]));
sPlotStore->setAxesAuto(false);
} else {
mp_raise_TypeError("the first argument to axis() must be an iterable of the form [xmin, xmax, ymin, ymax]");
}
}
// Build the return value
mp_obj_t coords[4];
coords[0] = mp_obj_new_float(sPlotStore->xMin());
coords[1] = mp_obj_new_float(sPlotStore->xMax());
coords[2] = mp_obj_new_float(sPlotStore->yMin());
coords[3] = mp_obj_new_float(sPlotStore->yMax());
return mp_obj_new_tuple(4, coords);
}
/* bar(x, height, width, bottom)
* 'x', 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of
* scalar.
* 'width' default value is 0.8
* 'bottom' default value is None
* */
// TODO: accept keyword args?
mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) {
assert(sPlotStore != nullptr);
mp_obj_t * xItems;
mp_obj_t * hItems;
mp_obj_t * wItems;
mp_obj_t * bItems;
// x arg
size_t xLength = extractArgument(args[0], &xItems);
// height arg
size_t hLength = extractArgumentAndValidateSize(args[1], xLength, &hItems);
// width arg
size_t wLength = 1;
if (n_args >= 3) {
wLength = extractArgumentAndValidateSize(args[2], xLength, &wItems);
} else {
wItems = m_new(mp_obj_t, 1);
wItems[0] = mp_obj_new_float(0.8f);
}
// bottom arg
size_t bLength = 1;
if (n_args >= 4) {
bLength = extractArgumentAndValidateSize(args[3], xLength, &bItems);
} else {
bItems = m_new(mp_obj_t, 1);
bItems[0] = mp_obj_new_float(0.0f);
}
KDColor color = Palette::nextDataColor(&paletteIndex);
for (size_t i=0; i<xLength; i++) {
mp_float_t iH = mp_obj_get_float(hItems[hLength > 1 ? i : 0]);
mp_float_t iW = mp_obj_get_float(wItems[wLength > 1 ? i : 0]);
mp_float_t iB = mp_obj_get_float(bItems[bLength > 1 ? i : 0]);
mp_float_t iX = mp_obj_get_float(xItems[i])-iW/2.0;
mp_float_t iYStart = iH < 0.0 ? iB : iB + iH;
mp_float_t iYEnd = iH < 0.0 ? iB + iH : iB;
sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iX+iW), mp_obj_new_float(iYStart), mp_obj_new_float(iYEnd), color); // TODO: use float_binary_op?
}
return mp_const_none;
}
mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) {
assert(sPlotStore != nullptr);
if (n_args == 0) {
// Toggle the grid visibility
sPlotStore->setGridRequested(!sPlotStore->gridRequested());
} else {
sPlotStore->setGridRequested(mp_obj_is_true(args[0]));
}
return mp_const_none;
}
/* hist(x, bins)
* 'x' array
* 'bins': (default value 10)
* - int (number of bins)
* - sequence of bins
* */
mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) {
assert(sPlotStore != nullptr);
// Sort data to easily get the minimal and maximal value and count bin sizes
mp_obj_t * xItems;
size_t xLength = extractArgument(args[0], &xItems);
if (xLength == 0) {
return mp_const_none;
}
mp_obj_t xList = mp_obj_new_list(xLength, xItems);
mp_obj_list_sort(1, &xList, (mp_map_t*)&mp_const_empty_map);
mp_obj_list_get(xList, &xLength, &xItems);
assert(xLength > 0);
mp_float_t min = mp_obj_get_float(xItems[0]);
mp_float_t max = mp_obj_get_float(xItems[xLength - 1]);
mp_obj_t * edgeItems;
size_t nBins;
// bin arg
if (n_args >= 2 && (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list))) {
size_t nEdges;
mp_obj_get_array(args[1], &nEdges, &edgeItems);
nBins = nEdges -1;
} else {
nBins = 10;
if (n_args >= 2) {
nBins = mp_obj_get_int(args[1]);
}
mp_float_t binWidth = (max-min)/nBins;
// Create a array of bins
edgeItems = m_new(mp_obj_t, nBins + 1);
// Handle empty range case
if (max - min <= FLT_EPSILON) {
binWidth = 1.0;
nBins = 1;
}
// Fill the bin edges list
for (int i = 0; i < nBins+1; i++) {
edgeItems[i] = mp_obj_new_float(min+i*binWidth);
}
}
// Initialize bins list
mp_obj_t * binItems = m_new(mp_obj_t, nBins);
for (size_t i=0; i<nBins; i++) {
binItems[i] = MP_OBJ_NEW_SMALL_INT(0);
}
// Fill bins list by linearly scanning the x and incrementing the bin count
// Linearity is enabled thanks to sorting
size_t binIndex = 0;
size_t xIndex = 0;
while (binIndex < nBins) {
mp_float_t lowerBound = mp_obj_get_float(edgeItems[binIndex]);
// Skip xItem if below the lower bound
while (xIndex < xLength && mp_obj_get_float(xItems[xIndex]) < lowerBound) {
xIndex++;
}
mp_float_t upperBound = mp_obj_get_float(edgeItems[binIndex+1]);
while (xIndex < xLength && (mp_obj_get_float(xItems[xIndex]) < upperBound || (binIndex == nBins - 1 && mp_obj_get_float(xItems[xIndex]) == upperBound))) {
assert(mp_obj_get_float(xItems[xIndex]) >= lowerBound);
// Increment the bin count
binItems[binIndex] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(binItems[binIndex]) + 1);
xIndex++;
}
binIndex++;
}
KDColor color = Palette::nextDataColor(&paletteIndex);
for (size_t i=0; i<nBins; i++) {
sPlotStore->addRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color);
}
return mp_const_none;
}
/* scatter(x, y)
* - x, y: list
* - x, y: scalar
* */
mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) {
assert(sPlotStore != nullptr);
mp_obj_t * xItems, * yItems;
size_t length = extractArgumentsAndCheckEqualSize(x, y, &xItems, &yItems);
KDColor color = Palette::nextDataColor(&paletteIndex);
for (size_t i=0; i<length; i++) {
sPlotStore->addDot(xItems[i], yItems[i], color);
}
return mp_const_none;
}
/* plot(x, y) plots the curve (x, y)
* plot(y) plots the curve x as index array ([0,1,2...],y)
* */
mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) {
assert(sPlotStore != nullptr);
mp_obj_t * xItems, * yItems;
size_t length;
if (n_args == 1) {
length = extractArgument(args[0], &yItems);
// Create the default xItems: [0, 1, 2,...]
xItems = m_new(mp_obj_t, length);
for (int i = 0; i < length; i++) {
xItems[i] = mp_obj_new_float((float)i);
}
} else {
assert(n_args == 2);
length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems);
}
KDColor color = Palette::nextDataColor(&paletteIndex);
for (int i=0; i<(int)length-1; i++) {
sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false);
}
return mp_const_none;
}
mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) {
assert(sPlotStore != nullptr);
// Input parameter validation
mp_obj_get_float(x);
mp_obj_get_float(y);
mp_obj_str_get_str(s);
sPlotStore->addLabel(x, y, s);
return mp_const_none;
}
mp_obj_t modpyplot_show() {
if (sPlotStore->isEmpty()) {
return mp_const_none;
}
MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
env->displayViewController(sPlotController);
return mp_const_none;
}

View File

@@ -0,0 +1,15 @@
#include <py/obj.h>
mp_obj_t modpyplot___init__();
void modpyplot_gc_collect();
void modpyplot_flush_used_heap();
mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args);
mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y);
mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s);
mp_obj_t modpyplot_show();

View File

@@ -0,0 +1,33 @@
#include "modpyplot.h"
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 2, modpyplot_hist);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 2, modpyplot_plot);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text);
STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) },
{ MP_ROM_QSTR(MP_QSTR_arrow), MP_ROM_PTR(&modpyplot_arrow_obj) },
{ MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) },
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) },
{ MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) },
{ MP_ROM_QSTR(MP_QSTR_hist), MP_ROM_PTR(&modpyplot_hist_obj) },
{ MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) },
{ MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) },
{ MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&modpyplot_text_obj) },
};
STATIC MP_DEFINE_CONST_DICT(modpyplot_module_globals, modpyplot_module_globals_table);
const mp_obj_module_t modpyplot_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&modpyplot_module_globals,
};

View File

@@ -0,0 +1,14 @@
#include "plot_controller.h"
namespace Matplotlib {
void PlotController::viewWillAppear() {
m_store->initRange();
curveView()->reload();
}
void PlotController::viewDidDisappear() {
m_store->flush();
}
}

View File

@@ -0,0 +1,27 @@
#ifndef PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H
#define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H
#include <apps/shared/zoom_and_pan_curve_view_controller.h>
#include "plot_view.h"
#include "plot_store.h"
namespace Matplotlib {
class PlotController : public Shared::ZoomAndPanCurveViewController {
public:
PlotController(PlotStore * store) : Shared::ZoomAndPanCurveViewController(nullptr), m_store(store), m_view(m_store) {}
void viewWillAppear() override;
void viewDidDisappear() override;
protected:
Shared::CurveView * curveView() override { return &m_view; }
Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_store; }
private:
PlotStore * m_store;
PlotView m_view;
};
}
#endif

View File

@@ -0,0 +1,219 @@
#include "plot_store.h"
namespace Matplotlib {
PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(),
m_axesRequested(true),
m_axesAuto(true),
m_gridRequested(false)
{
flush();
}
void PlotStore::flush() {
m_dots = mp_obj_new_list(0, nullptr);
m_segments = mp_obj_new_list(0, nullptr);
m_rects = mp_obj_new_list(0, nullptr);
m_labels = mp_obj_new_list(0, nullptr);
m_axesRequested = true;
m_axesAuto = true;
m_gridRequested = false;
}
bool PlotStore::isEmpty() {
return MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_dots)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_segments)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_rects)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_labels)) == 0;
}
// Iterators
template <class T>
PlotStore::ListIterator<T> PlotStore::ListIterator<T>::Begin(mp_obj_t list) {
ListIterator<T> it;
mp_obj_list_get(list, &(it.m_numberOfTuples), &(it.m_tuples));
return it;
}
template <class T>
PlotStore::ListIterator<T> PlotStore::ListIterator<T>::End(mp_obj_t list) {
ListIterator<T> it;
mp_obj_list_get(list, &(it.m_numberOfTuples), &(it.m_tuples));
if (it.m_numberOfTuples > 0) {
it.m_tupleIndex = it.m_numberOfTuples;
}
return it;
}
template <class T>
PlotStore::ListIterator<T> & PlotStore::ListIterator<T>::operator++() {
if (m_tupleIndex < m_numberOfTuples) {
m_tupleIndex++;
}
return *this;
}
template <class T>
bool PlotStore::ListIterator<T>::operator!=(const PlotStore::ListIterator<T> & it) const {
return m_tupleIndex != it.m_tupleIndex;
};
template <class T>
T PlotStore::ListIterator<T>::operator*() {
return T(m_tuples[m_tupleIndex]);
};
void checkFloatType(mp_obj_t * elements, size_t nbOfElements) {
for (int i = 0; i < nbOfElements; i++) {
// TODO: we don't take advantage of the fact that we extracted the value at the sametime... Maybe change the way things are done, build the c objects in addItem instead of allocating them on the python heap? Or use float array in python?
mp_float_t value;
if (!mp_obj_get_float_maybe(elements[i], &value)) {
mp_raise_TypeError("argument should be a number");
}
}
}
// Dot
template class PlotStore::ListIterator<PlotStore::Dot>;
PlotStore::Dot::Dot(mp_obj_t tuple) {
mp_obj_t * elements;
mp_obj_get_array_fixed_n(tuple, 3, &elements);
m_x = mp_obj_get_float(elements[0]);
m_y = mp_obj_get_float(elements[1]);
m_color = KDColor::RGB16(mp_obj_get_int(elements[2]));
}
void PlotStore::addDot(mp_obj_t x, mp_obj_t y, KDColor c) {
mp_obj_t color = mp_obj_new_int(c);
mp_obj_t items[3] = {x, y, color};
checkFloatType(items, 2);
mp_obj_t tuple = mp_obj_new_tuple(3, items);
mp_obj_list_append(m_dots, tuple);
}
// Segment
template class PlotStore::ListIterator<PlotStore::Segment>;
PlotStore::Segment::Segment(mp_obj_t tuple) {
mp_obj_t * elements;
mp_obj_get_array_fixed_n(tuple, 6 , &elements);
m_xStart = mp_obj_get_float(elements[0]);
m_yStart = mp_obj_get_float(elements[1]);
m_xEnd = mp_obj_get_float(elements[2]);
m_yEnd = mp_obj_get_float(elements[3]);
m_color = KDColor::RGB16(mp_obj_get_int(elements[4]));
m_arrow = elements[5] == mp_const_true;
}
void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge) {
mp_obj_t color = mp_obj_new_int(c);
mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowEdge ? mp_const_true : mp_const_false};
checkFloatType(items, 4);
mp_obj_t tuple = mp_obj_new_tuple(6, items);
mp_obj_list_append(m_segments, tuple);
}
// Rect
template class PlotStore::ListIterator<PlotStore::Rect>;
PlotStore::Rect::Rect(mp_obj_t tuple) {
mp_obj_t * elements;
mp_obj_get_array_fixed_n(tuple, 5, &elements);
m_left = mp_obj_get_float(elements[0]);
m_right = mp_obj_get_float(elements[1]);
m_top = mp_obj_get_float(elements[2]);
m_bottom = mp_obj_get_float(elements[3]);
m_color = KDColor::RGB16(mp_obj_get_int(elements[4]));
}
void PlotStore::addRect(mp_obj_t left, mp_obj_t right, mp_obj_t top, mp_obj_t bottom, KDColor c) {
mp_obj_t color = mp_obj_new_int(c);
mp_obj_t items[5] = {left, right, top, bottom, color};
checkFloatType(items, 4);
mp_obj_t tuple = mp_obj_new_tuple(5, items);
mp_obj_list_append(m_rects, tuple);
}
// Label
template class PlotStore::ListIterator<PlotStore::Label>;
PlotStore::Label::Label(mp_obj_t tuple) {
mp_obj_t * elements;
mp_obj_get_array_fixed_n(tuple, 3, &elements);
m_x = mp_obj_get_float(elements[0]);
m_y = mp_obj_get_float(elements[1]);
m_string = mp_obj_str_get_str(elements[2]);
}
void PlotStore::addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string) {
mp_obj_t items[3] = {x, y, string};
checkFloatType(items, 2);
if (!mp_obj_is_str(string)) {
mp_raise_TypeError("argument should be a string");
}
mp_obj_t tuple = mp_obj_new_tuple(3, items);
mp_obj_list_append(m_labels, tuple);
}
// Axes
static inline float minFloat(float x, float y) { return x < y ? x : y; }
static inline float maxFloat(float x, float y) { return x > y ? x : y; }
void updateRange(float * xMin, float * xMax, float * yMin, float * yMax, float x, float y) {
if (!std::isnan(x) && !std::isinf(x) && !std::isnan(y) && !std::isinf(y)) {
*xMin = minFloat(*xMin, x);
*xMax = maxFloat(*xMax, x);
*yMin = minFloat(*yMin, y);
*yMax = maxFloat(*yMax, y);
}
}
void checkPositiveRangeAndAddMargin(float * min, float * max) {
if (*min > *max) {
*min = - Shared::Range1D::k_default;
*max = Shared::Range1D::k_default;
return;
}
// Add margins
float margin = (*max - *min)/10.0f;
if (margin < FLT_EPSILON) {
margin = 1.0f;
}
*min -= margin;
*max += margin;
}
void PlotStore::initRange() {
if (m_axesAuto) {
float xMin = FLT_MAX;
float xMax = -FLT_MAX;
float yMin = FLT_MAX;
float yMax = -FLT_MAX;
for (PlotStore::Dot dot : dots()) {
updateRange(&xMin, &xMax, &yMin, &yMax, dot.x(), dot.y());
}
for (PlotStore::Label label : labels()) {
updateRange(&xMin, &xMax, &yMin, &yMax, label.x(), label.y());
}
for (PlotStore::Segment segment : segments()) {
updateRange(&xMin, &xMax, &yMin, &yMax, segment.xStart(), segment.yStart());
updateRange(&xMin, &xMax, &yMin, &yMax, segment.xEnd(), segment.yEnd());
}
for (PlotStore::Rect rectangle : rects()) {
updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.left(), rectangle.top());
updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.right(), rectangle.bottom());
}
checkPositiveRangeAndAddMargin(&xMin, &xMax);
checkPositiveRangeAndAddMargin(&yMin, &yMax);
setXMin(xMin);
setXMax(xMax);
setYMin(yMin);
setYMax(yMax);
}
}
}

View File

@@ -0,0 +1,142 @@
#ifndef PYTHON_MATPLOTLIB_PLOT_STORE_H
#define PYTHON_MATPLOTLIB_PLOT_STORE_H
//#include <apps/shared/curve_view_range.h>
#include <apps/shared/interactive_curve_view_range.h>
extern "C" {
#include <py/runtime.h>
}
namespace Matplotlib {
class PlotStore : public Shared::InteractiveCurveViewRange {
public:
PlotStore();
void flush();
bool isEmpty();
// Iterators
template <class T>
class ListIterator {
public:
static ListIterator Begin(mp_obj_t list);
static ListIterator End(mp_obj_t list);
T operator*();
ListIterator & operator++();
bool operator!=(const ListIterator & it) const;
private:
ListIterator() : m_tupleIndex(0) {}
mp_obj_t * m_tuples;
size_t m_numberOfTuples;
size_t m_tupleIndex;
};
template <class T>
class Iterable {
public:
Iterable(mp_obj_t list) : m_list(list) {}
T begin() const { return T::Begin(m_list); }
T end() const { return T::End(m_list); }
private:
mp_obj_t m_list;
};
// Dot
class Dot {
public:
Dot(mp_obj_t tuple);
float x() const { return m_x; }
float y() const { return m_y; }
KDColor color() const { return m_color; }
private:
float m_x;
float m_y;
KDColor m_color;
};
void addDot(mp_obj_t x, mp_obj_t y, KDColor c);
Iterable<ListIterator<Dot>> dots() { return Iterable<ListIterator<Dot>>(m_dots); }
// Segment
class Segment {
public:
Segment(mp_obj_t tuple);
float xStart() const { return m_xStart; }
float yStart() const { return m_yStart; }
float xEnd() const { return m_xEnd; }
float yEnd() const { return m_yEnd; }
bool isArrow() const { return m_arrow; }
KDColor color() const { return m_color; }
private:
float m_xStart;
float m_yStart;
float m_xEnd;
float m_yEnd;
bool m_arrow;
KDColor m_color;
};
void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge);
Iterable<ListIterator<Segment>> segments() { return Iterable<ListIterator<Segment>>(m_segments); }
// Rect
class Rect {
public:
Rect(mp_obj_t tuple);
float left() const { return m_left; }
float right() const { return m_right; }
float top() const { return m_top; }
float bottom() const { return m_bottom; }
KDColor color() const { return m_color; }
private:
float m_left;
float m_right;
float m_top;
float m_bottom;
KDColor m_color;
};
void addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c);
Iterable<ListIterator<Rect>> rects() { return Iterable<ListIterator<Rect>>(m_rects); }
// Label
class Label {
public:
Label(mp_obj_t tuple);
float x() const { return m_x; }
float y() const { return m_y; }
const char * string() const { return m_string; }
private:
float m_x;
float m_y;
const char * m_string;
};
void addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string);
Iterable<ListIterator<Label>> labels() { return Iterable<ListIterator<Label>>(m_labels); }
void setAxesRequested(bool b) { m_axesRequested = b; }
bool axesRequested() const { return m_axesRequested; }
void setAxesAuto(bool b) { m_axesAuto = b; }
void initRange();
void setGridRequested(bool b) { m_gridRequested = b; }
bool gridRequested() const { return m_gridRequested; }
private:
mp_obj_t m_dots; // List of (x, y, color)
mp_obj_t m_labels; // List of (x, y, string)
mp_obj_t m_segments; // List of (x, y, dx, dy, style, color)
mp_obj_t m_rects; // List of (x, y, w, h, color)
bool m_axesRequested;
bool m_axesAuto;
bool m_gridRequested;
};
}
#endif

View File

@@ -0,0 +1,80 @@
#include "plot_view.h"
namespace Matplotlib {
void PlotView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, KDColorWhite);
if (m_store->gridRequested()) {
drawGrid(ctx, rect);
}
// Draw labels below all figures because they're drawn on a white rectangle.
// TODO: we could blend them in the background by adding a parameter to drawLabelsAndGraduations.
if (m_store->axesRequested()) {
drawAxes(ctx, rect);
drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true);
drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true);
}
for (PlotStore::Dot dot : m_store->dots()) {
traceDot(ctx, rect, dot);
}
for (PlotStore::Label label : m_store->labels()) {
traceLabel(ctx, rect, label);
}
for (PlotStore::Segment segment : m_store->segments()) {
traceSegment(ctx, rect, segment);
}
for (PlotStore::Rect rectangle : m_store->rects()) {
traceRect(ctx, rect, rectangle);
}
}
void PlotView::traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const {
drawDot(ctx, r, dot.x(), dot.y(), dot.color());
}
void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segment) const {
drawSegment(
ctx, r,
segment.xStart(), segment.yStart(),
segment.xEnd(), segment.yEnd(),
segment.color()
);
if (segment.isArrow()) {
float dx = segment.xEnd() - segment.xStart();
float dy = segment.yEnd() - segment.yStart();
drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color());
}
}
static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const {
KDCoordinate left = std::round(floatToPixel(Axis::Horizontal, rect.left()));
KDCoordinate right = std::round(floatToPixel(Axis::Horizontal, rect.right()));
KDCoordinate top = std::round(floatToPixel(Axis::Vertical, rect.top()));
KDCoordinate bottom = std::round(floatToPixel(Axis::Vertical, rect.bottom()));
KDRect pixelRect(
left,
top,
maxKDCoordinate(right - left, 1), // Rectangle should at least be visible
bottom - top
);
ctx->fillRect(pixelRect, rect.color());
}
void PlotView::traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) const {
drawLabel(ctx, r,
label.x(), label.y(), label.string(),
KDColorBlack,
RelativePosition::After,
RelativePosition::After
);
}
}

View File

@@ -0,0 +1,24 @@
#ifndef PYTHON_MATPLOTLIB_PLOT_VIEW_H
#define PYTHON_MATPLOTLIB_PLOT_VIEW_H
#include <apps/shared/labeled_curve_view.h>
#include "plot_store.h"
namespace Matplotlib {
class PlotView : public Shared::LabeledCurveView {
public:
PlotView(PlotStore * s) : Shared::LabeledCurveView(s), m_store(s) {}
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
void traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const;
void traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segment) const;
void traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const;
void traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) const;
PlotStore * m_store;
};
}
#endif

View File

@@ -130,12 +130,16 @@ typedef long mp_off_t;
extern const struct _mp_obj_module_t modion_module;
extern const struct _mp_obj_module_t modkandinsky_module;
extern const struct _mp_obj_module_t modmatplotlib_module;
extern const struct _mp_obj_module_t modpyplot_module;
extern const struct _mp_obj_module_t modtime_module;
extern const struct _mp_obj_module_t modturtle_module;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_ion), MP_ROM_PTR(&modion_module) }, \
{ MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&modkandinsky_module) }, \
{ MP_ROM_QSTR(MP_QSTR_matplotlib), MP_ROM_PTR(&modmatplotlib_module) }, \
{ MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot), MP_ROM_PTR(&modpyplot_module) }, \
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \
{ MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \

View File

@@ -20,6 +20,7 @@ extern "C" {
#include "py/stackctrl.h"
#include "mphalport.h"
#include "mod/turtle/modturtle.h"
#include "mod/matplotlib/pyplot/modpyplot.h"
}
static MicroPython::ScriptProvider * sScriptProvider = nullptr;
@@ -81,6 +82,10 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) {
mp_obj_print_helper(&mp_plat_print, (mp_obj_t)nlr.ret_val, PRINT_EXC);
mp_print_str(&mp_plat_print, "\n");
/* End of mp_obj_print_exception. */
// Flush the store if an error is encountered to avoid being stuck with a full memory
modpyplot_flush_used_heap();
// TODO: do the same for other modules?
}
// Disable the user interruption
@@ -94,13 +99,6 @@ void MicroPython::ExecutionEnvironment::interrupt() {
mp_keyboard_interrupt();
}
void MicroPython::ExecutionEnvironment::setSandboxIsDisplayed(bool display) {
if (m_sandboxIsDisplayed && !display) {
modturtle_view_did_disappear();
}
m_sandboxIsDisplayed = display;
}
extern "C" {
extern const void * _stack_start;
extern const void * _stack_end;
@@ -176,6 +174,7 @@ void gc_collect(void) {
gc_collect_start();
modturtle_gc_collect();
modpyplot_gc_collect();
/* get the registers.
* regs is the also the last object on the stack so the stack is bound by

View File

@@ -4,6 +4,7 @@
extern "C" {
#include <stddef.h>
}
#include <escher/view_controller.h>
namespace MicroPython {
@@ -14,21 +15,23 @@ public:
class ExecutionEnvironment {
public:
ExecutionEnvironment() : m_sandboxIsDisplayed(false) {}
ExecutionEnvironment() {}
static ExecutionEnvironment * currentExecutionEnvironment();
void runCode(const char * );
virtual const char * inputText(const char * prompt) { return nullptr; }
virtual void displaySandbox() {}
virtual void hideSandbox() {}
// Sandbox
void displaySandbox() { displayViewController(sandbox()); }
virtual ViewController * sandbox() { return nullptr; }
virtual void resetSandbox() {}
// Generic View Controller
virtual void displayViewController(ViewController * controller) {}
virtual void hideAnyDisplayedViewController() {}
virtual void printText(const char * text, size_t length) {}
virtual void refreshPrintOutput() {}
void interrupt();
void setSandboxIsDisplayed(bool display);
protected:
bool sandboxIsDisplayed() const { return m_sandboxIsDisplayed; }
private:
bool m_sandboxIsDisplayed;
};
void init(void * heapStart, void * heapEnd);
@@ -36,6 +39,6 @@ void deinit();
void registerScriptProvider(ScriptProvider * s);
void collectRootsAtAddress(char * address, int len);
};
}
#endif